206 lines
6.1 KiB
C#
206 lines
6.1 KiB
C#
using System;
|
|
using Customer;
|
|
using UnityEngine;
|
|
using UnityEngine.AI;
|
|
using static Customer.MoodState;
|
|
using Random = UnityEngine.Random;
|
|
|
|
public class CustomerController : MonoBehaviour, IObjectParentHolder {
|
|
private NavMeshAgent _navMeshAgent;
|
|
private Vector3 _target;
|
|
|
|
public SellCounter TargetCounter { get; private set; }
|
|
|
|
[Header("WaitTime")] [SerializeField] private float _minWaitTime = 5.0f;
|
|
[SerializeField] private float _maxWaitTime = 10.0f;
|
|
|
|
[Header("BuyChace")] [SerializeField] private float _buyChance = 0.5f;
|
|
[SerializeField] private float _buyChanceIncrease = 0.1f;
|
|
[SerializeField] private float _buyChanceDecrease = 0.1f;
|
|
|
|
|
|
[SerializeField] private Transform _objectHolder;
|
|
|
|
private Object _currentObject;
|
|
|
|
private float _waitTime;
|
|
|
|
private CustomerVisibleController _visibleController;
|
|
|
|
public MoodState State => _visibleController.GetState();
|
|
|
|
private Vector3 _exitPosition;
|
|
public event Action<SellCounter, CustomerController> OnCustomerLeft;
|
|
|
|
|
|
private CustomerState _state = CustomerState.GoingToCounter;
|
|
|
|
//enum
|
|
public enum CustomerState {
|
|
GoingToCounter,
|
|
WaitingToBuy,
|
|
Buying,
|
|
WalkingToExit
|
|
}
|
|
|
|
private void Awake() {
|
|
_navMeshAgent = GetComponent<NavMeshAgent>();
|
|
_visibleController = GetComponent<CustomerVisibleController>();
|
|
|
|
_visibleController.SetState(Normal);
|
|
}
|
|
|
|
private void Update() {
|
|
switch (_state) {
|
|
case CustomerState.GoingToCounter:
|
|
if (_navMeshAgent.remainingDistance <= _navMeshAgent.stoppingDistance) {
|
|
OnDestinationReached();
|
|
}
|
|
|
|
break;
|
|
case CustomerState.WaitingToBuy:
|
|
WaitToBuy();
|
|
break;
|
|
case CustomerState.Buying:
|
|
BuyItem();
|
|
break;
|
|
case CustomerState.WalkingToExit:
|
|
CheckIfReachedExit();
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
}
|
|
|
|
private void CheckIfReachedExit() {
|
|
if (_navMeshAgent.remainingDistance <= _navMeshAgent.stoppingDistance) {
|
|
Debug.Log("Bye :p");
|
|
CustomerManager.Instance.CustomerDies(this);
|
|
Destroy(this.gameObject);
|
|
}
|
|
}
|
|
|
|
private bool ShouldBuyItem() {
|
|
//This should be a function that checks if a customer should buy an item
|
|
//For example, if the item is worth 10 bucks, and the player sets the price to 20, the customer should not buy it since its too expensive
|
|
|
|
//if an item is prices higher then X% of the base price, the customer should not buy it
|
|
Object obj = TargetCounter.GetObject();
|
|
if (obj == null) {
|
|
Debug.LogError("Counter has no object");
|
|
return false;
|
|
}
|
|
|
|
float price = obj.ObjectSo.basePrice;
|
|
float sellPrice = TargetCounter.GetSellingPrice();
|
|
bool isBroken = obj.IsBroken;
|
|
|
|
float difference = Mathf.Abs(price - sellPrice);
|
|
float percentage = difference / price;
|
|
|
|
//Log this for now
|
|
Debug.Log("Difference: " + difference + " Percentage: " + percentage);
|
|
//Random differnece between 0.1 and 0.2;
|
|
float diff = Random.Range(_buyChanceDecrease, _buyChanceIncrease);
|
|
|
|
var calculatedBuyChance = _buyChance;
|
|
|
|
if (isBroken) {
|
|
//Customer should be less likely to buy broken items
|
|
calculatedBuyChance -= 0.1f;
|
|
}
|
|
|
|
if (percentage > calculatedBuyChance + diff) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public void SetDestination(Vector3 position) {
|
|
_target = position;
|
|
_navMeshAgent.SetDestination(_target);
|
|
}
|
|
|
|
public void SetTargetCounter(SellCounter counter) {
|
|
TargetCounter = counter;
|
|
|
|
float angle = Random.Range(0, 360);
|
|
Vector3 offset = new Vector3(Mathf.Cos(angle), 0, Mathf.Sin(angle));
|
|
this.SetDestination(counter.transform.position + offset);
|
|
}
|
|
|
|
private void BuyItem() {
|
|
if (TargetCounter == null) {
|
|
Debug.LogError("Customer has no target counter");
|
|
return;
|
|
}
|
|
|
|
if (!ShouldBuyItem()) {
|
|
Debug.Log("Customer should not buy item");
|
|
this.SetDestination(_exitPosition);
|
|
_state = CustomerState.WalkingToExit;
|
|
_visibleController.SetState(Angry);
|
|
SoundFXController.Instance.PlayVillagerAngryFX();
|
|
return;
|
|
}
|
|
|
|
Debug.Log("Customer bought item: " + TargetCounter.GetObject().ObjectSo.objectName + " for: " +
|
|
TargetCounter.GetSellingPrice());
|
|
_visibleController.SetState(Normal);
|
|
TargetCounter.SellItem(this);
|
|
SoundFXController.Instance.PlayItemBoughtFX();
|
|
SoundFXController.Instance.PlayVillagerHappyFX();
|
|
this.SetDestination(_exitPosition);
|
|
_state = CustomerState.WalkingToExit;
|
|
OnCustomerLeft?.Invoke(TargetCounter, this); //Notify the customer manager that the customer left
|
|
}
|
|
|
|
private void OnDestinationReached() {
|
|
//should tell the counter there is a customer waiting;
|
|
Debug.Log("Customer reached destination for Counter: " + TargetCounter.name);
|
|
_state = CustomerState.WaitingToBuy;
|
|
_waitTime = Random.Range(_minWaitTime, _maxWaitTime);
|
|
}
|
|
|
|
void OnDrawGizmosSelected() {
|
|
Gizmos.color = Color.red;
|
|
Gizmos.DrawWireSphere(_target, 0.5f);
|
|
}
|
|
|
|
void WaitToBuy() {
|
|
_waitTime -= Time.deltaTime;
|
|
if (_waitTime <= 0) {
|
|
_state = CustomerState.Buying;
|
|
}
|
|
}
|
|
|
|
public Transform GetHolderTransform() {
|
|
return _objectHolder;
|
|
}
|
|
|
|
public void SetObject(Object obj) {
|
|
_currentObject = obj;
|
|
}
|
|
|
|
public Object GetObject() {
|
|
return _currentObject;
|
|
}
|
|
|
|
public void ClearObject() {
|
|
_currentObject = null;
|
|
}
|
|
|
|
public bool HasObject() {
|
|
return _currentObject != null;
|
|
}
|
|
|
|
public void SetExitPosition(Vector3 position) {
|
|
_exitPosition = position;
|
|
}
|
|
|
|
|
|
public void SetState(CustomerState state) {
|
|
_state = state;
|
|
}
|
|
} |