Asked by Coder

using UnityEngine;

public class MonsterBehavior : MonoBehaviour
{
[Header("Target")]
public Transform target; // Assign player transform in inspector (or use tag auto-find below)

[Header("Movement")]
public float moveSpeed = 2f; // Movement speed (units/second)
public float stopDistance = 1.5f; // Distance at which the monster stops moving toward the target

[Header("Rotation")]
public float rotationSpeed = 5f; // Higher = faster turning

[Header("Options")]
public bool findPlayerByTag = true; // If true and target is null, tries to find GameObject tagged "Player"
public string playerTag = "Player";

// Optional: reference to animator to control walking animation
public Animator animator;
private readonly int animSpeedHash = Animator.StringToHash("Speed");

void Start()
{
if (target == null && findPlayerByTag)
{
GameObject p = GameObject.FindGameObjectWithTag(playerTag);
if (p != null) target = p.transform;
}
}

void Update()
{
if (target == null) return;

// Compute horizontal direction to player (ignore vertical difference for rotation)
Vector3 toTarget = target.position - transform.position;
Vector3 toTargetFlat = new Vector3(toTarget.x, 0f, toTarget.z);
float distance = toTargetFlat.magnitude;

// Smoothly rotate to face the player (only yaw / y-axis)
if (toTargetFlat.sqrMagnitude > 0.0001f)
{
Quaternion targetRotation = Quaternion.LookRotation(toTargetFlat.normalized);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
}

// Move forward while farther than stopDistance
if (distance > stopDistance)
{
Vector3 forward = transform.forward;
Vector3 newPosition = transform.position + forward * moveSpeed * Time.deltaTime;
transform.position = newPosition;

if (animator) animator.SetFloat(animSpeedHash, 1f);
}
else
{
if (animator) animator.SetFloat(animSpeedHash, 0f);
}
}

// Optional: draw stopDistance in editor for convenience
void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, stopDistance);
}
}

Monster spazzes out and changes color when he gets close.

All Answers 1

Answered by GPT-5 mini AI
You're very close — the spazzing is almost certainly caused by the movement/rotation logic oscillating/overshooting when the monster gets within the stop radius, and the color change is likely a side-effect of the animator rapidly flipping states (or an animation keyframing the material/color) as the Speed parameter jumps between values. Below I explain what's happening and give a safer, corrected script plus a few extra tips.

Why it happens
- You move using transform.forward while you rotate toward the player. When the monster is close, small angle differences cause it to move a little past the stopping radius, then rotation flips it back, producing jitter/oscillation.
- The animator Speed parameter is set directly to 1 or 0. If it toggles rapidly at the threshold the animator might switch between clips that change the material or other properties, producing a color flicker.
- Slerp factor usage can also be problematic if interpreted as a speed; using Quaternion.Slerp(transform.rotation, targetRot, rotationSpeed * Time.deltaTime) treats rotationSpeed as a fraction per second (not degrees) — RotateTowards is more intuitive (degrees/sec).

Fixes
- Move toward the exact target position on the horizontal plane (Vector3.MoveTowards or CharacterController/ Rigidbody APIs) instead of using transform.forward.
- Rotate smoothly using Quaternion.RotateTowards (degrees/sec) or clamp the Slerp factor.
- Smooth the animator parameter using Animator.SetFloat with damping so it doesn't flip instantly.
- Ensure your animations do not keyframe material color, or remove that track if they do.

Corrected script (safe, simple changes)
Replace your Update() with this version (keeps inspector fields similar):

public float rotationSpeed = 180f; // degrees per second now

void Update()
{
if (target == null) return;

// horizontal positions only
Vector3 targetPosFlat = new Vector3(target.position.x, transform.position.y, target.position.z);
Vector3 toTarget = targetPosFlat - transform.position;
float distance = toTarget.magnitude;

// Smooth rotation: use RotateTowards (rotationSpeed is degrees/sec)
if (toTarget.sqrMagnitude > 0.0001f)
{
Quaternion targetRotation = Quaternion.LookRotation(toTarget.normalized);
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
}

// Move directly toward the player to avoid overshoot/oscillation
if (distance > stopDistance)
{
Vector3 next = Vector3.MoveTowards(transform.position, targetPosFlat, moveSpeed * Time.deltaTime);
transform.position = next;

// Smooth animator parameter (damp time 0.1s)
if (animator) animator.SetFloat(animSpeedHash, 1f, 0.1f, Time.deltaTime);
}
else
{
if (animator) animator.SetFloat(animSpeedHash, 0f, 0.1f, Time.deltaTime);
}
}

Why this helps
- MoveTowards always moves straight to the target position (no overshoot due to forward direction mismatch).
- RotateTowards uses degrees/sec which is clearer and avoids weird Slerp factor behavior.
- Animator.SetFloat with damping prevents rapid toggling and removes abrupt animation transitions that might affect color.

Extra suggestions
- If your monster uses physics, move it with Rigidbody.MovePosition or a CharacterController rather than transform.position.
- If you want pathfinding and obstacle avoidance, use a NavMeshAgent — it handles rotation/movement/stopping nicely.
- Double-check your animation clips in the Animator for any material/color keyframes. If present, remove them or use a separate Animator layer for material changes.
- If the color change persists, add a small debug: print the animator state or check if any script changes material.color when within range.

If you want, paste your Animator Controller or the exact animation clips — I can point out any color keys or show how to smooth transitions further.