Detecting a Continuous Collision/Player Position and Reseting Timers,Detect a collision for a certain number of seconds
Hi all,
I've been tearing my hair out with this, and while there seem to be a few very similar questions out there I've yet to really figure this out.
The setting: The player needs to remain in a certain area for 3 seconds in order to take a photo. Currently I'm using a plane with a mesh trigger as the 'photo zone.' If they stay touching the plane for 3 seconds, the photo is taken (i.e. bool photoTaken = true). If they leave the photo zone before the 3 seconds are up, the timer resets.
I found a very similar question here and used that code to get started. It basically works, but annoyingly photo-taking 'process' seems to start every frame, leading to enormous spam in the console. I'd like to have the process start once for each entrance into the zone, rather than firing continuously.
I'm pretty new to Unity and C# so I'm sure I'm doing something a bit silly. Posting my code (attached to the player GameObject, minus other things like movement for brevity) for reference.
Thanks in advance for any advice you might have!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public bool photoTaken = false;
public float photoCountdown = 3.0f;
public bool inPhotoZone = false;
// Start is called before the first frame update
void Start()
{
playerRb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
// Collision timer
if (inPhotoZone == true)
{
photoCountdown -= Time.deltaTime;
if (photoCountdown < 0)
{
photoCountdown = 0;
}
}
else if (inPhotoZone == false)
{
photoCountdown = 3f;
}
}
// Check for searchlight and photo zone collisions
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Searchlight"))
{
Debug.Log("!");
}
else if (other.gameObject.CompareTag("Photo Zone"))
{
Debug.Log("Steady...");
inPhotoZone = true;
}
}
// Check player remains in photo zone
private void OnTriggerStay(Collider other)
{
if (other.gameObject.CompareTag("Photo Zone") && inPhotoZone == true)
{
Debug.Log("Ho-o-old it...");
if(photoCountdown <= 0)
{
photoTaken = true;
Debug.Log("*snap!*");
}
}
}
// Reset timer if player leaves photo zone
private void OnTriggerExit(Collider other)
{
if (other.gameObject.CompareTag("Photo Zone") && photoTaken == false)
{
Debug.Log("Darn it! Hold steady won't you?");
inPhotoZone = false;
}
}
}
Answer by Dsiak · Nov 25, 2021 at 11:03 PM
Hi @JNGRichardson thats a very good formatted question. The reason you are getting spammed is because once it reaches the condition to snap a pic it will keep on reaching the condition every frame, therefore snapping every frame. Try making it so the condition is only true for one frame, you already half way there all I did was add another boolean check to the snapping.
private void OnTriggerStay(Collider other)
{
if (other.gameObject.CompareTag("Photo Zone") && inPhotoZone == true && photoTaken == false)
{
Debug.Log("Ho-o-old it...");
if (photoCountdown <= 0)
{
photoTaken = true;
Debug.Log("*snap!*");
}
}
}
Now that leaves you with a "Ho-o-old it..." spam, so keeping true to the methods I'll add another check to the "Ho-o-old it..." text:
private void OnTriggerStay(Collider other)
{
if (other.gameObject.CompareTag("Photo Zone") && inPhotoZone == true && photoTaken == false)
{
if (!isHoldingIt)
{
Debug.Log("Ho-o-old it...");
isHoldingIt = true;
}
if (photoCountdown <= 0)
{
photoTaken = true;
Debug.Log("*snap!*");
}
}
}
That should give you a single stream of:
But if you allow me to be ever so nosy I'll much rather you use Coroutines, that way you can more easily pass it parameters for different photo zones and you can make use of the "yield return new WaitForSeconds();" The code with Coroutines would be something like this:
// Check for searchlight and photo zone collisions
private void OnTriggerEnter(Collider other)
{
Debug.Log("Enter Trigger");
if (other.gameObject.CompareTag("Searchlight"))
{
Debug.Log("!");
}
else if (other.gameObject.CompareTag("Photo Zone"))
{
Debug.Log("Steady...");
inPhotoZone = true;
StartCoroutine (HoldingItCoroutine())
}
}
IEnumerator HoldingItCoroutine()
{
Debug.Log("Ho-o-old it...");
yield return new WaitForSeconds(3);
photoTaken = true;
Debug.Log("*snap!*");
}
private void OnTriggerExit(Collider other)
{
if (other.gameObject.CompareTag("Photo Zone") && photoTaken == false)
{
StopCoroutine(HoldingItCoroutine());
Debug.Log("Darn it! Hold steady won't you?");
inPhotoZone = false;
}
}
Your answer
Follow this Question
Related Questions
Collision issue, Plz help 1 Answer
OnTriggerExit not working 0 Answers
Having the worst time making OnCollision work... Strange. 0 Answers
Unity 2D does not detect collisions 0 Answers
How i can fix a player controller bug? 0 Answers