Refactoring of status system to prevent bug w/ events

This commit is contained in:
Antoine H 2021-01-27 15:31:18 +01:00
parent fd8306645b
commit e89483d612
13 changed files with 487 additions and 113 deletions

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 960e132629e28d84dad6b20f39361d54
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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()

View file

@ -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()

View file

@ -62,6 +62,6 @@ public class SoftObstacle : MonoBehaviour
void OnDestroy()
{
EventManager.Instance.destroyEvent(gameObject);
EventManager.Instance.removeEvent(gameObject);
}
}

View file

@ -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();
}
}

View file

@ -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