I would reply this with a body problem:
It is best to not entry the enemies’ canSeePlayer property utilizing the participant controller – that is not its job.
Following the Single Accountability Precept, every class ought to have one job:
-
PlayerContoller‘s job is to manage the participant character, reworking inputs into actions / actions of the participant’s avatar. -
“
enemies” or what I will nameNPCVision‘s job is to deal with non-player-characters’ line-of-sight checks.
Deciding when and how one can finish the sport / managing the “recreation over” UI isn’t a part of both of those duties. That is particular to a recreation mode / degree or gameplay context. It is simple to think about circumstances the place we would need to re-use a controllable participant character and NPCs with imaginative and prescient in a setting the place getting seen should not be an on the spot recreation over, like in a tutorial, or with pleasant / impartial NPCs.
So, I would separate your “get seen = Recreation Over” logic into its personal script that controls this gameplay mode:
public class DontGetSeenMode : MonoBehaviour {
[SerializeField]
GameObject _gameOverScreen;
bool _gameIsOver;
// Subscribe to NPC imaginative and prescient occasions to know when to set off recreation over.
void OnEnable() {
NPCVision.onPlayerSeen += GotSeen;
}
// Unsubscribe when this mode is disabled / unloaded with the scene.
void OnDisable() {
NPCVision.onPlayerSeen -= GotSeen;
}
void GotSeen() {
// Guarantee we solely set off Recreation Over as soon as between resets.
if (!_gameIsOver)
StartCoroutine(GameOverSequence());
}
IEnumerator GameOverSequence() {
_gameIsOver = true;
// Disable the participant controller
FindAnyObjectByType().enabled = false;
// TODO: Play "This enemy noticed you" animations / results.
// Wait a beat for the participant to see / course of how they misplaced.
yield return new WaitForSeconds(1f);
// Present the sport over display.
_gameOverScreen.SetActive(true);
}
}
To drive this, your NPC imaginative and prescient script can expose an occasion fired when an NPC spots the participant:
public class NPCVision : MonoBehaviour {
public static occasion System.Motion onPlayerSeen;
[SerializeField] LayerMask obstructionLayer;
public bool canSeePlayer { get; non-public set; }
non-public void OnTriggerStay2D(Collider2D different) {
if (different.CompareTag("Participant")) {
Vector2 directionToTarget = (different.rework.place - rework.place);
float distanceToTarget = directionToTarget.magnitude;
bool noticed = !Physics2D.Raycast(rework.place, directionToTarget, distanceToTarget, obstructionLayer);
if (noticed && !canSeePlayer) {
if (onPlayerSeen != null) onPlayerSeen.Invoke();
}
canSeePlayer = noticed;
}
}
non-public void OnTriggerExit2D(Collider2D different) {
if (different.CompareTag("Participant")) canSeePlayer = false;
}
}
This ensures every script has a well-defined duty, and just one purpose to alter:
-
PlayerControllersolely must be up to date once you need to change how the participant character controls. -
NPCVisionsolely must be up to date once you need to change how NPC line-of-sight checks work. -
DontGetSeenModesolely must be up to date once you need to change the way you deal with the sport over set off and related messaging.
That is going to be far more versatile and maintainable than mixing these duties between the courses.
