KuhBall.cs

Component attached to a game object representing a roaming 'KuhBall' entity. It checks ground beneath the object, periodically picks a new yaw target, plays an idle sound sometimes, and smoothly rotates the Rigidbody toward the target while on ground or when slow in air.

Native Interop
using Sandbox;
using System;
using System.Threading.Tasks;

public sealed class KuhBall : Component
{
	[Property] SoundEvent IdleSound;
	[Property] public SoundEvent DamageSound;
	Rigidbody Body;
	Rotation targetRot;
	float TurnCooldown = 4f;
	TimeUntil NextTurn;
	Random random;

	protected override void OnStart()
	{
		random = new Random();
		Body = GameObject.GetComponent<Rigidbody>();
	}

	protected override void OnUpdate()
	{
		SceneTraceResult GroundCheck = Scene.Trace.Ray(WorldPosition, WorldPosition + WorldRotation.Down * 1)
			.IgnoreGameObjectHierarchy(GameObject)
			.WithoutTags("enemy", "player")
			.Run();
		// DebugOverlay.Trace(GroundCheck);

		if ( GroundCheck.Hit ) 
		{
			if ( NextTurn ) 
			{
				targetRot = WorldRotation.Angles().WithYaw(WorldRotation.Yaw() + random.Int(-45, 45)).WithPitch(0);
				NextTurn = TurnCooldown;
				if ( random.Int( 1, 10 ) > 5 )
				{
					SoundHandle mooHandle = Sound.Play( IdleSound, WorldPosition );
					mooHandle.Parent = GameObject;
					mooHandle.FollowParent = true;
				}
			}

			Body.SmoothRotate(targetRot, 0.6f, Time.Delta);

		}
		else if (Body.Velocity.Length < 10)
		{
			// Log.Info("Trying rotate");
			Body.SmoothRotate( targetRot.Angles().WithYaw(WorldRotation.Yaw()), 0.4f, Time.Delta );

		}
		
		
	}

}