Refactoring of status system to prevent bug w/ events
This commit is contained in:
parent
fd8306645b
commit
e89483d612
13 changed files with 487 additions and 113 deletions
8
Assets/Scripts/Characters.meta
Normal file
8
Assets/Scripts/Characters.meta
Normal file
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 960e132629e28d84dad6b20f39361d54
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -18,56 +18,26 @@ public class Client_controller : MonoBehaviour, IUsable
|
|||
Animator animator;
|
||||
string _status;
|
||||
string _prevStatus;
|
||||
string _lastStatusRequest=null;
|
||||
// private readonly object balanceLock = new object();
|
||||
// bool updatingStatus=false;
|
||||
HashSet<string> _availStatus = new HashSet<string>(){"entering", "waiting", "consuming", "leaving", "event"};
|
||||
public string status
|
||||
{
|
||||
get{ return _status;}
|
||||
//BEWARE : Set is only a request. The status is only really set in update.
|
||||
set{
|
||||
if (_availStatus.Contains(value))
|
||||
_prevStatus=_status;
|
||||
_status = value;
|
||||
animator.SetTrigger(_status); //Update status in animator
|
||||
// Debug.Log(gameObject.name+" "+_status);
|
||||
switch (value)
|
||||
{
|
||||
case "entering":
|
||||
navObstacle.enabled = false;
|
||||
agent.enabled = true;
|
||||
if(UIWaitingTimer != null)
|
||||
UIWaitingTimer.gameObject.SetActive(false);
|
||||
break;
|
||||
case "waiting":
|
||||
EventManager.Instance.startCoroutine(gameObject);
|
||||
//Switch Agent to obstacle if waiting
|
||||
agent.Warp(assigedPos); //Make sure agent become static at right position
|
||||
agent.enabled = false;
|
||||
navObstacle.enabled = true;
|
||||
|
||||
if(UIWaitingTimer != null)
|
||||
{
|
||||
UIWaitingTimer.DisplayIcon(true);
|
||||
UIWaitingTimer.SetValue(1.0f);
|
||||
UIWaitingTimer.gameObject.SetActive(true);
|
||||
}
|
||||
break;
|
||||
case "consuming":
|
||||
EventManager.Instance.startCoroutine(gameObject);
|
||||
if(UIWaitingTimer != null)
|
||||
UIWaitingTimer.gameObject.SetActive(false);
|
||||
break;
|
||||
case "event":
|
||||
case "leaving":
|
||||
EventManager.Instance.stopCoroutine(gameObject);
|
||||
navObstacle.enabled = false;
|
||||
agent.enabled = true;
|
||||
if(UIWaitingTimer != null)
|
||||
UIWaitingTimer.gameObject.SetActive(false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// navObstacle.enabled = value=="waiting";
|
||||
// agent.enabled = value!="waiting";
|
||||
{
|
||||
if(value==_status)
|
||||
Debug.LogWarning(gameObject.name+" status is set twice to:"+value);
|
||||
else //Request change of status
|
||||
{
|
||||
// if(_lastStatusRequest!=null)
|
||||
// Debug.LogWarning(gameObject.name+" status request("+_lastStatusRequest+") is overriden by : "+value);
|
||||
_lastStatusRequest = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,6 +48,7 @@ public class Client_controller : MonoBehaviour, IUsable
|
|||
|
||||
//Navigation
|
||||
Vector2 assigedPos; //Chair to sit or destination to stay (leave)
|
||||
Vector2 currentObjective; //Current destination to reach
|
||||
NavMeshAgent agent;
|
||||
NavMeshObstacle navObstacle; //Obstacle for other agents
|
||||
|
||||
|
@ -125,21 +96,66 @@ public class Client_controller : MonoBehaviour, IUsable
|
|||
if(destination is null)
|
||||
{
|
||||
status=_prevStatus;
|
||||
// NavMeshHit hit;
|
||||
// NavMesh.SamplePosition(gameObject.transform.position, out hit, agent.height*2, NavMesh.AllAreas);
|
||||
// agent.Warp(hit.position);
|
||||
if(agent.enabled)
|
||||
agent.SetDestination(assigedPos);
|
||||
else
|
||||
gameObject.transform.position=assigedPos;
|
||||
currentObjective=assigedPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
status="event";
|
||||
agent.SetDestination((Vector2)destination);
|
||||
currentObjective=(Vector2)destination;
|
||||
}
|
||||
}
|
||||
|
||||
//Update client attributes in fonction of the newStatus. Should only be called once by Update.
|
||||
protected void updateStatus(string newStatus)
|
||||
{
|
||||
switch (newStatus)
|
||||
{
|
||||
case "entering":
|
||||
navObstacle.enabled = false;
|
||||
agent.enabled = true;
|
||||
if(UIWaitingTimer != null)
|
||||
UIWaitingTimer.gameObject.SetActive(false);
|
||||
break;
|
||||
case "waiting":
|
||||
EventManager.Instance.startCoroutine(gameObject);
|
||||
//Switch Agent to obstacle if waiting
|
||||
// agent.Warp(assigedPos); //Make sure agent become static at right position
|
||||
agent.enabled = false;
|
||||
navObstacle.enabled = true;
|
||||
|
||||
if(UIWaitingTimer != null)
|
||||
{
|
||||
UIWaitingTimer.DisplayIcon(true);
|
||||
UIWaitingTimer.gameObject.SetActive(true);
|
||||
}
|
||||
break;
|
||||
case "consuming":
|
||||
EventManager.Instance.startCoroutine(gameObject);
|
||||
if(UIWaitingTimer != null)
|
||||
UIWaitingTimer.gameObject.SetActive(false);
|
||||
break;
|
||||
case "event":
|
||||
case "leaving":
|
||||
EventManager.Instance.stopCoroutine(gameObject);
|
||||
navObstacle.enabled = false;
|
||||
agent.enabled = true;
|
||||
if(UIWaitingTimer != null)
|
||||
UIWaitingTimer.gameObject.SetActive(false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
//Navigation
|
||||
if(agent.enabled) //Assign destination
|
||||
agent.SetDestination(currentObjective);
|
||||
else //Warp to destination
|
||||
gameObject.transform.position=currentObjective;
|
||||
|
||||
if(status=="event"&&!agent.enabled)
|
||||
Debug.LogWarning("Wrong status update : "+ gameObject.name + _prevStatus + status +" "+ _lastStatusRequest);
|
||||
}
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
|
@ -163,8 +179,8 @@ public class Client_controller : MonoBehaviour, IUsable
|
|||
agent.updateRotation = false;
|
||||
agent.updateUpAxis = false;
|
||||
//Get target
|
||||
assigedPos = ClientManager.Instance.assignTarget(); //Chair to go
|
||||
agent.SetDestination(assigedPos);
|
||||
currentObjective = assigedPos = ClientManager.Instance.assignTarget(); //Chair to go
|
||||
// agent.SetDestination(assigedPos);
|
||||
//Assign Random priority to prevent two agent blocking each other
|
||||
agent.avoidancePriority=Random.Range(0, 99);
|
||||
|
||||
|
@ -174,9 +190,25 @@ public class Client_controller : MonoBehaviour, IUsable
|
|||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
//Update status if it was requested
|
||||
if(_lastStatusRequest !=null)
|
||||
{
|
||||
_prevStatus=_status;
|
||||
_status = _lastStatusRequest;
|
||||
|
||||
animator.SetTrigger(_status); //Update status in animator
|
||||
updateStatus(_status);
|
||||
|
||||
_lastStatusRequest = null;
|
||||
|
||||
// Debug.Log(gameObject.name+" "+_status);
|
||||
}
|
||||
|
||||
//Navigation
|
||||
// Debug.Log(gameObject.name + " navigation : "+ agent.isStopped + " " + agent.remainingDistance);
|
||||
Debug.DrawLine(gameObject.transform.position, agent.destination, Color.blue, 0.0f);
|
||||
|
||||
|
||||
if(status=="entering" && !agent.pathPending && agent.remainingDistance==0) //Reached seat ?
|
||||
{
|
||||
status="waiting";
|
||||
|
@ -193,8 +225,8 @@ public class Client_controller : MonoBehaviour, IUsable
|
|||
{
|
||||
//Leave tavern
|
||||
status = "leaving";
|
||||
assigedPos = ClientManager.Instance.assignTarget(assigedPos, true); //Request leaving target
|
||||
agent.SetDestination(assigedPos);
|
||||
currentObjective = assigedPos = ClientManager.Instance.assignTarget(assigedPos, true); //Request leaving target
|
||||
// agent.SetDestination(assigedPos);
|
||||
}
|
||||
else if(UIWaitingTimer != null) //Update UI Waiting timer
|
||||
UIWaitingTimer.SetValue(waitTimer/waitingTime);
|
||||
|
@ -228,10 +260,15 @@ public class Client_controller : MonoBehaviour, IUsable
|
|||
}
|
||||
}
|
||||
|
||||
else if(status=="leaving" && !agent.pathPending && agent.remainingDistance==0)
|
||||
else if(status=="leaving" && !agent.pathPending && agent.remainingDistance<0.5) //Reached exit ?
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
else if(status=="event" && !agent.pathPending && agent.remainingDistance==0) //Reached event ?
|
||||
{
|
||||
assignToEvent(); //In case events already finished, come back to normal
|
||||
}
|
||||
}
|
||||
|
||||
void OnDestroy()
|
|
@ -10,7 +10,7 @@ using UnityEngine.AI;
|
|||
public class HardObstacle : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
float lifeTime = -1.0f; //Time before self-destruct (Negative value to prevent self-destruct)
|
||||
float lifeTime= -1.0f, waitTime= 30.0f; //Time active/waiting before self-destruct (Negative value to prevent self-destruct)
|
||||
float lifeTimer;
|
||||
|
||||
List<Client_controller> angryClients = new List<Client_controller>(); //Clients in the fight
|
||||
|
@ -25,7 +25,7 @@ public class HardObstacle : MonoBehaviour
|
|||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
lifeTimer=lifeTime;
|
||||
lifeTimer=waitTime; //Start by waiting client
|
||||
|
||||
ObsCollider = GetComponent<Collider2D>();
|
||||
|
||||
|
@ -39,14 +39,10 @@ public class HardObstacle : MonoBehaviour
|
|||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
if(animator.GetBool("active fight") && lifeTimer>0)
|
||||
{
|
||||
lifeTimer -= Time.deltaTime;
|
||||
if(lifeTimer<0)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
lifeTimer -= Time.deltaTime;
|
||||
if(lifeTimer<0)
|
||||
Destroy(gameObject);
|
||||
|
||||
}
|
||||
|
||||
void OnTriggerEnter2D(Collider2D other)
|
||||
|
@ -54,21 +50,25 @@ public class HardObstacle : MonoBehaviour
|
|||
Client_controller newClient = other.GetComponent<Client_controller>();
|
||||
if(newClient!=null && !angryClients.Contains(newClient))
|
||||
{
|
||||
angryClients.RemoveAll(item => item == null); //In case clients have been destroyed before event start, remove them
|
||||
|
||||
if(newClient.status!="event") //Make sure to set right status
|
||||
newClient.assignToEvent(gameObject.transform.position);
|
||||
angryClients.Add(newClient);
|
||||
|
||||
// Debug.Log("New fighting client. Current nb : "+angryClients.Count);
|
||||
|
||||
if(angryClients.Count>1)//Start fight
|
||||
{
|
||||
foreach(Client_controller client in angryClients) //Turn off client (to merge for a fight)
|
||||
client.gameObject.SetActive(false);
|
||||
client.gameObject.SetActive(false);
|
||||
|
||||
animator.SetBool("active fight", true);
|
||||
|
||||
|
||||
//Block movement
|
||||
Obstacle.enabled=true;
|
||||
ObsCollider.isTrigger=false; //Trigger becoming solid
|
||||
|
||||
lifeTimer=lifeTime; //Time before end of the fight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ public class HardObstacle : MonoBehaviour
|
|||
client.assignToEvent(); //Restore previous behavior
|
||||
}
|
||||
|
||||
EventManager.Instance.destroyEvent(gameObject);
|
||||
EventManager.Instance.removeEvent(gameObject);
|
||||
}
|
||||
|
||||
void OnApplicationQuit()
|
||||
|
|
|
@ -62,6 +62,6 @@ public class SoftObstacle : MonoBehaviour
|
|||
|
||||
void OnDestroy()
|
||||
{
|
||||
EventManager.Instance.destroyEvent(gameObject);
|
||||
EventManager.Instance.removeEvent(gameObject);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ public sealed class EventManager : MonoBehaviour
|
|||
[SerializeField]
|
||||
float SpawnRange = 1.0f; //Range of an event spawn from its origin (real max distance = 2*range)
|
||||
[SerializeField]
|
||||
float spawnChance = 100.0f; //Probability of an event to spawn (%)
|
||||
float spawnChanceSoft = 100.0f, spawnChanceHard = 100.0f; //Probability of an event to spawn (%)
|
||||
[SerializeField]
|
||||
int maxSoftObs = 1, maxHardObs = 1; //Maximum active events
|
||||
|
||||
|
@ -39,7 +39,7 @@ public sealed class EventManager : MonoBehaviour
|
|||
private Dictionary<string,Object[]> eventPrefabs = new Dictionary<string,Object[]>();
|
||||
GameObject EventContainer=null;
|
||||
|
||||
//List of active event ID
|
||||
//List of active event
|
||||
List<GameObject> softObsList = new List<GameObject>();
|
||||
List<GameObject> hardObsList = new List<GameObject>();
|
||||
|
||||
|
@ -81,12 +81,31 @@ public sealed class EventManager : MonoBehaviour
|
|||
}
|
||||
|
||||
//Remove an event from the EventManager
|
||||
public void destroyEvent(GameObject eventObj)
|
||||
public void removeEvent(GameObject eventObj)
|
||||
{
|
||||
softObsList.Remove(eventObj);
|
||||
hardObsList.Remove(eventObj);
|
||||
}
|
||||
|
||||
//Destroy registered events. Levels : 2 = All events, 1 = Hard Obstacles
|
||||
public void cleanUp(int level=2)
|
||||
{
|
||||
if(level<1)
|
||||
Debug.Log("EventManager : Called cleanup w/ level inferior to 1. Nothing was done.");
|
||||
if(level>0) //Clean HardObstacles
|
||||
{
|
||||
foreach(GameObject obs in hardObsList)
|
||||
Destroy(obs);
|
||||
hardObsList.Clear();
|
||||
}
|
||||
if(level>1) //Clean SoftObstacles
|
||||
{
|
||||
foreach(GameObject obs in softObsList)
|
||||
Destroy(obs);
|
||||
softObsList.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
//Start an event coroutine for client
|
||||
public void startCoroutine(GameObject client)
|
||||
{
|
||||
|
@ -122,8 +141,9 @@ public sealed class EventManager : MonoBehaviour
|
|||
if(GameSystem.Instance.serviceOpen)
|
||||
{
|
||||
//Try to spawn softObs or hardObs randomly
|
||||
if(Random.value<0.5 && client.status=="consuming")
|
||||
EventManager.Instance.spawnSoftObs(clientObj.transform.position, spawnChance);
|
||||
if(Random.value<0.5f)
|
||||
if(client.status=="consuming") //Only spawn soft obs while consuming
|
||||
EventManager.Instance.spawnSoftObs(clientObj.transform.position, spawnChanceSoft);
|
||||
else
|
||||
{
|
||||
List<GameObject> otherClients = findNearClients(clientObj, 1.0f);
|
||||
|
@ -137,7 +157,7 @@ public sealed class EventManager : MonoBehaviour
|
|||
//TODO : Compute spawnChance w/ clients happiness
|
||||
Vector2 eventPos=(clientObj.transform.position+tgtClient.transform.position)/2; //Event pos between clients
|
||||
List<Client_controller> targetClients = new List<Client_controller>(){client, tgtClient.GetComponent<Client_controller>()};
|
||||
EventManager.Instance.spawnHardObs(targetClients, eventPos, spawnChance);
|
||||
EventManager.Instance.spawnHardObs(targetClients, eventPos, spawnChanceHard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -228,5 +248,6 @@ public sealed class EventManager : MonoBehaviour
|
|||
void OnDestroy()
|
||||
{
|
||||
StopAllCoroutines();
|
||||
cleanUp();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,16 @@ public sealed class GameSystem : MonoBehaviour
|
|||
{
|
||||
serviceTimer=serviceTime;
|
||||
serviceOpen=true;
|
||||
|
||||
Debug.Log("Service open !");
|
||||
}
|
||||
|
||||
public void endService()
|
||||
{
|
||||
serviceOpen=false;
|
||||
EventManager.Instance.cleanUp(1); //Remove hard obstacle
|
||||
|
||||
Debug.Log("Service closed !");
|
||||
}
|
||||
|
||||
//Change time scale
|
||||
|
@ -127,10 +137,7 @@ public sealed class GameSystem : MonoBehaviour
|
|||
if(UIServiceTimer != null)
|
||||
UIServiceTimer.SetValue(serviceTimer/serviceTime);
|
||||
if (serviceTimer < 0)
|
||||
{
|
||||
serviceOpen = false;
|
||||
Debug.Log("Service closed");
|
||||
}
|
||||
endService();
|
||||
}
|
||||
|
||||
//Temporary manual slowmode toggle
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue