Files
pgs/Assets/Scripts/NpcMovementController.cs

123 lines
4.0 KiB
C#
Raw Permalink Normal View History

2026-02-21 16:58:22 -08:00
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NpcMovementController : MonoBehaviour {
[SerializeField] private SpriteRenderer spriteRenderer;
[SerializeField] private Animator animator;
[SerializeField] private Rigidbody2D rigidBody;
[SerializeField] private float walkSpeed;
[Range(0f, 1f)] [SerializeField] private float walkProbability;
[Range(0f, 3f)] [SerializeField] private float smoothTime;
[SerializeField] private float minTimeIdle;
[SerializeField] private float maxTimeIdle;
[SerializeField] private float minTimeWalk;
[SerializeField] private float maxTimeWalk;
public Vector2 boundsX;
public bool isFacingRight;
public bool isWalking;
private Vector2 targetVelocity;
private Vector2 referenceVelocity = Vector2.zero;
private Vector2 myBounds;
// Start is called before the first frame update
void Awake() {
animator = gameObject.GetComponent<Animator>();
rigidBody = gameObject.GetComponent<Rigidbody2D>();
isFacingRight = true;
isWalking = false;
StartCoroutine("IdleWalkCoroutine");
myBounds = new Vector2(transform.position.x - boundsX.x, transform.position.x + boundsX.y);
}
private void FixedUpdate() {
// If you're about to walk off a ledge, don't.
bool isMoving = Mathf.Abs(rigidBody.velocity.x) > 0.001;
bool isMovingRight = rigidBody.velocity.x > 0;
if (isMoving && !CheckBounds(isMovingRight)) {
rigidBody.velocity = new Vector2(0f, rigidBody.velocity.y);
targetVelocity = new Vector2(0f, rigidBody.velocity.y);
} else if (Mathf.Abs(rigidBody.velocity.y) < 0.01f) {
Vector2 newVelocity = new Vector2(Vector2.SmoothDamp(rigidBody.velocity, targetVelocity, ref referenceVelocity, smoothTime).x,
rigidBody.velocity.y);
rigidBody.velocity = newVelocity;
}
animator.SetFloat("Speed", Mathf.Abs(rigidBody.velocity.x));
}
private bool TryToWalk(bool right, bool chase = false) {
if (CheckBounds(right)) {
if (right) {
targetVelocity = new Vector3(walkSpeed, 0, 0);
} else {
targetVelocity = new Vector3(-1 * walkSpeed, 0, 0);
}
if (isFacingRight != right) {
Flip();
}
return true;
}
return false;
}
private bool CheckBounds(bool right) {
if ((right && transform.position.x > myBounds.y) ||
(!right && transform.position.x < myBounds.x)) {
return false;
}
return true;
}
private IEnumerator IdleWalkCoroutine() {
while (true) {
if (ShouldWalk() && !isWalking) {
// Walk in a random direction.
isWalking = true;
if (Random.Range(0f, 1f) < 0.5f) {
// Walk left.
if (!TryToWalk(false)) {
TryToWalk(true);
}
} else {
// Walk right.
if (!TryToWalk(true)) {
TryToWalk(false);
}
}
yield return new WaitForSeconds(RandomWalkSeconds());
} else {
// Idle.
isWalking = false;
targetVelocity = Vector3.zero;
yield return new WaitForSeconds(RandomIdleSeconds());
}
}
}
private bool ShouldWalk() {
return Random.Range(0f, 1f) < walkProbability;
}
private float RandomIdleSeconds() {
return Random.Range(0f, 1f) * (maxTimeIdle - minTimeIdle) + minTimeIdle;
}
private float RandomWalkSeconds() {
return Random.Range(0f, 1f) * (maxTimeWalk - minTimeWalk) + minTimeWalk;
}
private void Flip() {
isFacingRight = !isFacingRight;
Vector3 scale = transform.localScale;
scale.x *= -1;
transform.localScale = scale;
}
}