using System.Collections.Generic; using UnityEngine; [RequireComponent(typeof(Rigidbody2D))] [RequireComponent(typeof(Collider2D))] public class TrickController : MonoBehaviour { [SerializeField] private string treatTag = "Interactable"; [SerializeField] private float moveSpeed = 3.5f; [SerializeField] private float targetRefreshInterval = 0.4f; [SerializeField] private float consumeDistance = 0.35f; [SerializeField] private float wanderInterval = 1.2f; private Rigidbody2D body; private Transform target; private float nextTargetTime; private Vector2 wanderDirection; private float nextWanderTime; private bool isCarried; private void Awake() { body = GetComponent(); body.bodyType = RigidbodyType2D.Dynamic; body.gravityScale = 1f; body.freezeRotation = true; body.collisionDetectionMode = CollisionDetectionMode2D.Continuous; body.interpolation = RigidbodyInterpolation2D.Interpolate; } private void Update() { if (isCarried) { return; } if (Time.time >= nextTargetTime) { target = FindNearestTreat(); if (target == null) { // If we can't find treats while we're tagged Interactable, keep moving. wanderDirection = Random.insideUnitCircle.normalized; if (wanderDirection.sqrMagnitude < 0.01f) { wanderDirection = Vector2.right; } nextWanderTime = Time.time + wanderInterval; } nextTargetTime = Time.time + targetRefreshInterval; } if (target == null && Time.time >= nextWanderTime) { wanderDirection = Random.insideUnitCircle.normalized; if (wanderDirection.sqrMagnitude < 0.01f) { wanderDirection = Vector2.right; } nextWanderTime = Time.time + wanderInterval; } TryConsumeTreat(); } private void FixedUpdate() { if (isCarried) { return; } Vector2 desiredVelocity; var stopForTreat = false; if (target != null) { var direction = ((Vector2)target.position - (Vector2)transform.position).normalized; desiredVelocity = new Vector2(direction.x * moveSpeed, 0f); stopForTreat = Vector2.Distance(transform.position, target.position) <= consumeDistance; } else { desiredVelocity = new Vector2(wanderDirection.x * (moveSpeed * 0.6f), 0f); } var velocity = body.linearVelocity; velocity.x = stopForTreat ? 0f : desiredVelocity.x; body.linearVelocity = velocity; } private Transform FindNearestTreat() { var treats = GameObject.FindGameObjectsWithTag(treatTag); if (treats == null || treats.Length == 0) { return null; } Transform best = null; var bestDistance = float.MaxValue; var origin = transform.position; for (var i = 0; i < treats.Length; i++) { var candidate = treats[i]; if (candidate == gameObject) { continue; } if (!candidate.activeInHierarchy) { continue; } if (!candidate.TryGetComponent(out var collider) || !collider.enabled) { continue; } var distance = Vector2.Distance(origin, candidate.transform.position); if (distance < bestDistance) { bestDistance = distance; best = candidate.transform; } } return best; } private void TryConsumeTreat() { if (isCarried) { return; } var hits = Physics2D.OverlapCircleAll(transform.position, consumeDistance); for (var i = 0; i < hits.Length; i++) { var hit = hits[i]; if (hit == null || hit.gameObject == gameObject || !hit.CompareTag(treatTag)) { continue; } Destroy(hit.gameObject); if (target == hit.transform) { target = null; } break; } } public void SetCarried(bool carried) { isCarried = carried; if (carried) { target = null; var velocity = body.linearVelocity; velocity.x = 0f; body.linearVelocity = velocity; } } }