customer requirement
download a character from mixamo
select your imported character and change the animation type to humanoid
click apply
add customerLayer to all your customer
using UnityEngine;
using UnityEngine.UI;
public class Customer : MonoBehaviour
{
public string request; // "Massage", "Sauna", "Facial"
public float patience = 10f;
public Slider patienceBar;
private bool isServed = false;
void Start()
{
// Random request
string[] services = { "Massage", "Sauna", "Facial" };
request = services[Random.Range(0, services.Length)];
patienceBar.maxValue = patience;
}
void Update()
{
if (!isServed)
{
patience -= Time.deltaTime;
patienceBar.value = patience;
if (patience <= 0)
{
GameManager.instance.CustomerLeftUnhappy();
Destroy(gameObject); // Customer leaves
}
}
}
public void Serve()
{
isServed = true;
GameManager.instance.CustomerServed();
Destroy(gameObject, 1f); // Leaves after being served
}
}
add collider to your customer
create 2 texts
MoneyText and reputation text
create empty and rename it as game manager and attach to it
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class GameManager : MonoBehaviour
{
public static GameManager instance;
public int money = 0;
public int reputation = 100;
public TMP_Text moneyText;
public TMP_Text reputationText;
void Awake()
{
instance = this;
}
public void CustomerServed()
{
money += 10;
reputation += 2;
UpdateUI();
}
public void CustomerLeftUnhappy()
{
reputation -= 5;
UpdateUI();
}
void UpdateUI()
{
moneyText.text = "Money: $" + money;
reputationText.text = "Reputation: " + reputation;
}
public void clickCustomer()
{
}
}
remember to fill in the instance in game manager script
right click your customer and create ui >> slider for your customer
render mode change to world space
add a panel and add text to show the text
reposition your canvas to zero zero
scale it to 0.01
delete the handle
using UnityEngine;
public class SpaStation : MonoBehaviour
{
public string stationType; // "Massage", "Sauna", "Facial"
private void OnTriggerEnter(Collider other)
{
Customer customer = other.GetComponent<Customer>();
if (customer != null && customer.request == stationType)
{
customer.Serve();
}
}
}
remember to add collider to your service place
attach SpaStation.cs to it
make your station type to Massage
for sauna game object put the station type as Sauna
for massage chair put the station type as Massage
add slider to your customer script
Idle (standing in queue).
Walk (customer moving to station).
Service (lying on bed, sitting in sauna, etc.).
Leave (walk out of spa).
remember to change all the human animation to humanoid and click apply
right click create animation> animator controller
add these parameter
Idle (bool)
Walk(bool)
Happy (trigger)
Angry (trigger)
Sitting (trigger)
Sleep (trigger)
select your animation idle and walk check the loop time
remember to add conditions to your transition
right click >> AI >> NavMesh Surface
click bake
select your customer and add component >> nav mesh agent
create empty, rename it as ExitPoint (p/s: case sensitive)
using UnityEngine;
using UnityEngine.AI; // Needed for NavMesh movement
public class Customer : MonoBehaviour
{
public string request; // "Massage", "Sauna", "Facial"
public float patience = 10f;
public UnityEngine.UI.Slider patienceBar;
private bool isServed = false;
private Animator animator;
private NavMeshAgent agent;
private Transform targetStation;
void Start()
{
animator = GetComponent<Animator>();
agent = GetComponent<NavMeshAgent>();
// Random request
string[] services = { "Massage", "Sauna", "Facial" };
request = services[Random.Range(0, services.Length)];
patienceBar.maxValue = patience;
animator.SetBool("Idle", true);
}
void Update()
{
if (!isServed)
{
patience -= Time.deltaTime;
patienceBar.value = patience;
if (patience <= 0)
{
LeaveUnhappy();
}
// Update walk animation
if (agent.velocity.magnitude > 0.1f)
{
animator.SetBool("Walk", true);
animator.SetBool("Idle", false);
}
else
{
animator.SetBool("Walk", false);
animator.SetBool("Idle", true);
}
}
}
public void GoToStation(Transform station)
{
targetStation = station;
agent.SetDestination(targetStation.position);
}
private void OnTriggerEnter(Collider other)
{
SpaStation station = other.GetComponent<SpaStation>();
if (station != null && station.stationType == request && !isServed)
{
StartCoroutine(ServiceRoutine(station));
}
}
private System.Collections.IEnumerator ServiceRoutine(SpaStation station)
{
isServed = true;
agent.isStopped = true;
// Play service animation
animator.SetTrigger("Service");
yield return new WaitForSeconds(3f); // Service duration
GameManager.instance.CustomerServed();
LeaveHappy();
}
private void LeaveHappy()
{
agent.isStopped = false;
animator.SetBool("Walk", true);
Vector3 exitPos = GameObject.Find("ExitPoint").transform.position;
agent.SetDestination(exitPos);
Destroy(gameObject, 5f);
}
private void LeaveUnhappy()
{
GameManager.instance.CustomerLeftUnhappy();
LeaveHappy();
}
}
void SpawnCustomer()
{
GameObject c = Instantiate(customerPrefab, spawnPoint.position, Quaternion.identity);
Customer customer = c.GetComponent<Customer>();
// Find a random station for their request
SpaStation[] stations = FindObjectsOfType<SpaStation>();
foreach (SpaStation s in stations)
{
if (s.stationType == customer.request)
{
customer.GoToStation(s.serviceSpot);
break;
}
}
}
create empty object and rename it as selectionManager
add new input system, find the directory, Assets/ starterAssets/Input System
double click this
add new actions
Add an Action called Click:
Add an Action called Point with:
Action Type: Value
Control Type: Vector2
Binding: <Mouse>/position
p/s: blue and larger text is the updated part
using UnityEngine;
#if ENABLE_INPUT_SYSTEM
using UnityEngine.InputSystem;
#endif
namespace StarterAssets
{
public class StarterAssetsInputs : MonoBehaviour
{
[Header("Character Input Values")]
public Vector2 move;
public Vector2 look;
public bool jump;
public bool sprint;
public bool click;
[Header("Movement Settings")]
public bool analogMovement;
[Header("Mouse Cursor Settings")]
public bool cursorLocked = true;
public bool cursorInputForLook = true;
#if ENABLE_INPUT_SYSTEM
public void OnMove(InputValue value)
{
MoveInput(value.Get<Vector2>());
}
public void OnLook(InputValue value)
{
if(cursorInputForLook)
{
LookInput(value.Get<Vector2>());
}
}
public void OnClick(InputValue value)
{
click = value.isPressed;
}
public void OnJump(InputValue value)
{
JumpInput(value.isPressed);
}
public void OnSprint(InputValue value)
{
SprintInput(value.isPressed);
}
#endif
public void MoveInput(Vector2 newMoveDirection)
{
move = newMoveDirection;
}
public void LookInput(Vector2 newLookDirection)
{
look = newLookDirection;
}
public void JumpInput(bool newJumpState)
{
jump = newJumpState;
}
public void SprintInput(bool newSprintState)
{
sprint = newSprintState;
}
private void OnApplicationFocus(bool hasFocus)
{
SetCursorState(cursorLocked);
}
private void SetCursorState(bool newState)
{
Cursor.lockState = newState ? CursorLockMode.Locked : CursorLockMode.None;
}
}
}
create empty object and rename it as customer selector, then fill in the empty slot
using StarterAssets;
using UnityEngine;
using UnityEngine.InputSystem;
public class CustomerSelector : MonoBehaviour
{
public static CustomerSelector instance;
// Start is called once before the first execution of Update after the MonoBehaviour is created
public StarterAssetsInputs inputActions;
public Camera mainCamera;
public Customer selectedCustomer;
public LayerMask customerLayer;
private void Update()
{
if(inputActions.click)
{
Debug.Log("click customer");
Ray ray = mainCamera.ScreenPointToRay(Mouse.current.position.ReadValue());
RaycastHit hit;
Debug.DrawRay(ray.origin, ray.direction * 100f, Color.red, 1f);
if (Physics.Raycast(ray, out hit, 100f, customerLayer))
{
Customer customer = hit.collider.GetComponent<Customer>();
Debug.Log(hit.collider.name);
if (customer != null)
{
selectedCustomer = customer;
Debug.Log("Selected customer with request: " + customer.request);
}
}
inputActions.click = false;
}
}
public void ClearSelection()
{
selectedCustomer = null;
}
}