I'm having issues playing Audio Clips in Unity.
I want my Shark to produce a "bite" sound when the player is detected but the sound is distorted.
The rest of the code is running as intended.
Can I have a code review and suggestion please?
What am I possibly doing wrong (when calling the Audio Source to Play)?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Shark2Controller : MonoBehaviour {
public Transform leftPoint;
public Transform rightPoint;
public float startSpeed;
public float swimSpeed;
private Rigidbody2D myRigidBody;
public bool swimmingRight;
public float superSpeed;
public Transform puntoA;
public Transform puntoB;
public LayerMask whatIsPlayer;
public bool playerDetected;
private Animator myAnim;
public AudioSource bite;
// Use this for initialization
void Start ()
{
myRigidBody = GetComponent<Rigidbody2D> ();
myAnim = GetComponent<Animator>();
swimSpeed = startSpeed;
}
// Update is called once per frame
void Update ()
{
playerDetected = Physics2D.OverlapArea (puntoA.position, puntoB.position, whatIsPlayer);
myAnim.SetBool ("Player Detected", playerDetected);
if (playerDetected)
{
swimSpeed = superSpeed;
bite.Play ();
}
if (swimmingRight && transform.position.x > rightPoint.position.x)
{
swimmingRight = false;
}
if (!swimmingRight && transform.position.x < leftPoint.position.x)
{
swimmingRight = true;
}
if (swimmingRight)
{
myRigidBody.velocity = new Vector3 (swimSpeed, myRigidBody.velocity.y, 0f);
transform.localScale = new Vector3 (1f, 1f, 1f);
}
else
{
myRigidBody.velocity = new Vector3 (-swimSpeed, myRigidBody.velocity.y, 0f);
transform.localScale = new Vector3 (-1f, 1f, 1f);
}
}
public void ResetShark2Speed()
{
swimSpeed = startSpeed;
}
}
One problem I see is that you're re-playing the sound at every screen update (based on your app's framerate). It's not clear if you want it to loop (since is placed inside a void Update function for repeated instructions) or you simply want it to play once per detection.
If Unity can detect when a sound is playing or has finished then use that to help fix this.
The looping logic is:
On each frame update, check if sound is already in "playing" mode.
If No... assume sound "ended" and you can now do bite.Play();.
Else-If Yes... let sound continue (maybe it'll be "ended" in a future frame check).
A pseudo-code example:
if (playerDetected == true)
{
swimSpeed = superSpeed;
if( bite.isPlaying == true)
{
//# Do nothing or whatever you need
}
else
{
//# Asssume it's not playing (eg: stopped, ended, not started, etc)
bite.Play ();
}
}
For once-per-detection:
public bool detect_snd_Played;
detect_Snd_Played = false; //# Not yet played since no "detect"
//# Update is called once per frame
void Update ()
{
if (playerDetected == true) { swimSpeed = superSpeed; }
if (detect_Snd_Played == false)
{
bite.Play ();
detect_Snd_Played = true; //# Stops future playback until you reset to false
}
}
This line detect_Snd_Played = true; should stop multiple playbacks until you reset. This could be if your player becomes "un-detected" by shark, and you can now reset for next time's new "detection" process...
Related
I am using unity version: 2021.3.6f1
I have setup indevidual animations for the player (four-way idle and walk) and I am using two blend trees which the script accesses and changes the variables moveX, moveY and is_idle. I am using the new Unity input system:
Screenshot of new Unity input system.
and cinemachine (cinemachine isn't causing problems though).
When I run the script, it has a weird jittering effect as if the animator keeps reseting the animation playback. Below is a video.
Link to video
Screenshot of the animator:
Screenshot of the animator
Here is the code in the player controller:
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour
{
public float moveSpeed = 1f;
public ContactFilter2D movementFilter;
public float collissionOffset = 0.05f;
Vector2 inputaxis;
Vector2 movementInput;
Vector2 prevMovementInput;
Rigidbody2D rb;
Animator animator;
List<RaycastHit2D> castCollissions = new List<RaycastHit2D>();
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
animator = GetComponent<Animator>();
}
private void FixedUpdate() {
if(movementInput != Vector2.zero){
bool success = TryMove(movementInput);
if(movementInput != prevMovementInput) {
animator.SetFloat("moveX", movementInput.x);
animator.SetFloat("moveY", movementInput.y);
prevMovementInput = movementInput;
}
if(!success){
success = TryMove(new Vector2(movementInput.x, 0));
if(!success){
success = TryMove(new Vector2(0, movementInput.y));
}
}
animator.SetBool("is_idle",false);
} else {
//animator.SetBool("is_idle", true);
}
}
private bool TryMove(Vector2 direction){
int count = rb.Cast(direction,
movementFilter,
castCollissions,
moveSpeed * Time.fixedDeltaTime + collissionOffset);
if(count == 0){
rb.MovePosition(rb.position + direction * moveSpeed * Time.fixedDeltaTime);
return true;
} else {
return false;
}
}
void UpdateAnimation_DONT_USE(){
// this is my origional function that would be called when I didn't have a blend tre
//animation direction
if(movementInput.x == 0.00d){
if(movementInput.y ==1.00d){
//up
animator.SetInteger("direction",1);
}
}else if(movementInput.x == 1.00d) {
if(movementInput.y == 0.00d){
//right
animator.SetInteger("direction",2);
}
}else if(movementInput.x == 0.00d) {
if(movementInput.y == -1.00d){
//down
animator.SetInteger("direction",3);
}
}else if(movementInput.x == -1.00d){
if(movementInput.y == 0.00d){
//left
animator.SetInteger("direction",4);
}
}
}
void OnMove(InputValue movementValue) {
movementInput = movementValue.Get<Vector2>();
}
}
The youtube video I used
First, I had lots of transition arrows going from the Any State block to all of the animation phases. When I tried it, the same result occured. I then watched a different youtube video which showed how to use a blend tree
I still have no idea what the problem is after trying a lot of different things.
If anyone can help, it would be much appreciated.
:)
I have found a solution meaning that I have to remake the game.
Even though I still don't know what the problem is, I used the default input system in a new prodject and it works fine.
Thanks to everyone who tried to help me! :)
The script is attached to two gameobjects.
One it's colliding area the collider is big enough so when the game start the player is already inside the collider area and then when he exit the area everything is working fine.
The problem is when I attached the object to another gameobject with collider but this time the collider s smaller and he is inside the bigger collider so now the player is entering the smaller collider and not first time exiting. but I want in both case to make the same effect.
If the player exit the collider he slow down wait then turn around and move inside back.
The same I want to make when the player getting closer to the fire flames slow down wait turn around and move back in it's just with the flames the player entering the collider area and then exit while in the bigger collider he first exit then enter.
Screenshot of the two colliders areas. The small one on the left is the one the player entering first and not exiting. The game start when the player is in the bigger collider area.
And the script :
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using UnityStandardAssets.Characters.ThirdPerson;
public class DistanceCheck : MonoBehaviour
{
public Transform targetToRotateTowards;
public Transform colliderArea;
public float lerpDuration;
public float rotationSpeed;
[TextArea(1, 2)]
public string textToShow;
public GameObject descriptionTextImage;
public TextMeshProUGUI text;
public ThirdPersonUserControl thirdPersonUserControl;
private Animator anim;
private float timeElapsed = 0;
private float startValue = 1;
private float endValue = 0;
private float valueToLerp = 0;
private bool startRotating = false;
private bool slowOnBack = true;
private bool exited = false;
private Vector3 exitPosition;
private float distance;
void Start()
{
anim = transform.GetComponent<Animator>();
}
private void FixedUpdate()
{
if (startRotating)
{
transform.rotation = Quaternion.RotateTowards(transform.rotation,
Quaternion.LookRotation(targetToRotateTowards.position - transform.position),
rotationSpeed * Time.deltaTime);
}
if (exitPosition != new Vector3(0, 0, 0) && slowOnBack)
{
distance = Vector3.Distance(transform.position, exitPosition);
}
if (distance > 5 && slowOnBack)
{
slowOnBack = false;
StartCoroutine(SlowDown());
}
}
private void OnTriggerExit(Collider other)
{
if (other.name == colliderArea.name)
{
exited = true;
slowOnBack = true;
exitPosition = transform.position;
thirdPersonUserControl.enabled = false;
descriptionTextImage.SetActive(true);
text.text = textToShow;
StartCoroutine(SlowDown());
}
}
private void OnTriggerEnter(Collider other)
{
if (other.name == colliderArea.name)
{
exited = false;
startRotating = false;
text.text = "";
descriptionTextImage.SetActive(false);
}
}
IEnumerator SlowDown()
{
timeElapsed = 0;
while (timeElapsed < lerpDuration)
{
valueToLerp = Mathf.Lerp(startValue, endValue, timeElapsed / lerpDuration);
anim.SetFloat("Forward", valueToLerp);
timeElapsed += Time.deltaTime;
yield return null;
}
if (exited)
{
yield return new WaitForSeconds(3f);
startRotating = true;
StartCoroutine(SpeedUp());
}
if (slowOnBack == false)
{
thirdPersonUserControl.enabled = true;
}
}
IEnumerator SpeedUp()
{
timeElapsed = 0;
while (timeElapsed < lerpDuration)
{
valueToLerp = Mathf.Lerp(endValue, startValue, timeElapsed / lerpDuration);
anim.SetFloat("Forward", valueToLerp);
timeElapsed += Time.deltaTime;
yield return null;
}
}
}
Two problems I'm facing right now :
The smaller collider the player enter it then exit and the bigger collider the player exit it then enter so I need to change somehow the OnTriggerExit/Enter behavior logic in the script. but how to make the logic ?
Maybe it's better to make the script to be on the player object only and make it some how generic so I can drag to it many colliders and to make the effect in each one of the colliders the problem is how to make a text field for each collider area ? Now because I attach the script to each collider object I have one colliderArea variable but if I want to make the script only attached to the player I need to change the colliderArea variable to a List<Transform> collidersAreas and then how to create a text field/area to each collider area in the List ?
I think I would do this by creating two tags, NoExit and NoEntry. Once the tags are created you can set the tag on the GameObjects that hold your colliders. Then you can check for tags in the OnTriggerEnter and OnTriggerExit and act accordingly.
I can't tell for sure which functionality you've got written is for which case, or if it's both - everything looks muddled. Ultimately what you should be going for is a function like RepositionPlayer, that moves them back to before they're violating the no entry or no exit rules, and then some kind of OnPlayerRepositioned event that restores their control.
I'll leave it up to you to split out your functionality, but in general I'd look to do something like the following:
private void OnTriggerExit(Collider other)
{
if (other.tag == "NoExit")
{
RepositionPlayer();
}
else if(other.tag == "NoEntry")
{
OnPlayerRepositioned();
}
}
private void OnTriggerEnter(Collider other)
{
if (other.tag == "NoExit")
{
OnPlayerRepositioned();
}
else if(other.tag == "NoEntry")
{
RepositionPlayer();
}
}
And again here it's not clear to me what you're trying to do to reposition the player, but it looks like it's something like:
private void RepositionPlayer()
{
// Stuff that needs to happen to reposition the player
exited = true;
slowOnBack = true;
exitPosition = transform.position;
thirdPersonUserControl.enabled = false;
descriptionTextImage.SetActive(true);
text.text = textToShow;
StartCoroutine(SlowDown());
}
private void OnPlayerRepositioned()
{
// stuff you need to do to clear the "repositioning" status
exited = false;
startRotating = false;
text.text = "";
descriptionTextImage.SetActive(false);
}
Splitting up the logic like this makes it easier to both read and maintain.
I am trying to make a platformer game. In the platformer game has a moving platform that makes everything it touches its transform's child while it touches it. Interestingly, whenever a stone(A movable object with a rigidbody and a polygon collider) touches the moving platform, the stone's scale goes haywire. Even though the scale reads the same on the transform component, it appears to be larger or smaller than it really is when touching it. When it stops touching the platform, the stone appears normal. Can anyone help me. Thank you.
This is the moving platform script that moves the platform around.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveTwoTransforms : MonoBehaviour
{
public Transform pointA;
public Transform pointB;
public bool HasReachedA;
public bool HasReacedB;
// Start is called before the first frame update
void Start()
{
transform.position = pointA.position;
HasReacedB = true;
HasReachedA = false;
StartCoroutine(GlideAround());
}
// Update is called once per frame
void Update()
{
}
public IEnumerator GlideAround()
{
while (true)
{
while (HasReachedA == false)
{
yield return new WaitForEndOfFrame();
transform.position = Vector2.Lerp(transform.position, pointA.position, 0.01f);
if ((Mathf.Abs(Vector2.Distance(pointA.position, transform.position)) < 0.01f))
{
HasReacedB = false;
HasReachedA = true;
}
}
while (HasReacedB == false)
{
yield return new WaitForEndOfFrame();
transform.position = Vector2.Lerp(transform.position, pointB.position, 0.01f);
if ((Mathf.Abs(Vector2.Distance(pointB.position, transform.position)) < 0.01f))
{
HasReacedB = true;
HasReachedA = false;
}
}
}
}
private void OnCollisionEnter2D(Collision2D collision)
{
if((collision.gameObject.tag == "Stone"|| collision.gameObject.tag == "Player") && (collision.transform.position.y - collision.transform.lossyScale.y / 2 >= transform.position.y))
{
collision.transform.parent = transform;
}
}
private void OnCollisionExit2D(Collision2D collision)
{
collision.transform.parent = null;
}
}
This is the stone script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RememberPositions : MonoBehaviour
{
public Vector3 StartingPosition;
public Vector3 StartingRotation;
public Vector3 StartingScale;
float StartRotation;
// Start is called before the first frame update
void Start()
{
StartingPosition = new Vector3(transform.position.x, transform.position.y, 0);
StartingRotation = new Vector3(0, 0, transform.position.z);
StartingScale = new Vector3(transform.localScale.x, transform.localScale.y, transform.localScale.z);
}
// Update is called once per frame
void Update()
{
transform.localScale = StartingScale;
}
}
There are no errors whatsoever and the rigidbody seems to be changing to the shape of the stone. Can anyone please specify the correct code I should use? Thank you.
If your moving platform is scaled, your stone will get scaled too. There are workarounds shown here to avoid this issue. One of them is adding a child GameObject to the platform, and moving the collision handling from the platform to that child.
I am trying to create a unity script that detects when the player has left a certain area using C# code only (no boundary boxes). My code should play a sound once the player leaves but the code is not working as expected and I cannot see a fault in the logic.
Expected behaviour
When the player steps outside the boundary, a sound will play once.
Actual Behaviour
The sound plays all the time no matter where the player is.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EX2BoundaryDetect : MonoBehaviour {
// create a GameObject to represent the player
public GameObject playerObject;
public bool leaveArea = false;
// create an Audio-clip object. This assumes we drag a sound file onto the myclip box in the Inspector.
public AudioClip myclip;
// Use this for initialization
void Start () {
// associate playerObject with the player. This assumes the First Person Controller is name "player
playerObject = GameObject.Find ("player");
// get the actual Sound file from the Inspector
GetComponent<AudioSource>().clip = myclip;
}
// Update is called once per frame
void Update () {
PlayAudio1();
if (leaveArea) {
GetComponent<AudioSource> ().Play ();
}
}
public void PlayAudio1 () {
// play the sound if the player is outside some boundaries
if (transform.position.x > 10) {
leaveArea = true;
}
if (transform.position.x < -29) {
leaveArea = true;
}
if (transform.position.z > 10) {
leaveArea = true;
}
if (transform.position.z < -29) {
leaveArea = true;
}
}
}
leaveArea is only set to false in the class definition. Once set to true, it may never be set to false again, and it may be inadvertently overwritten in the scene definition in the first place.
To fix this issue, set it to false at the beginning of Update:
void Update () {
leaveArea = false;
PlayAudio1();
if (leaveArea) {
GetComponent<AudioSource> ().Play ();
}
}
Also, GetComponent is an expensive action and it is good to avoid calling it in Update wherever possible. Therefore, you may want to move it into a class property and set it once in Start:
private AudioSource audioSource;
void Start () {
// associate playerObject with the player. This assumes the First Person Controller is name "player
playerObject = GameObject.Find ("player");
audioSource = GetComponent<AudioSource>();
// get the actual Sound file from the Inspector
audioSource.clip = myclip;
}
// Update is called once per frame
void Update () {
leaveArea = false;
PlayAudio1();
if (leaveArea) {
audioSource.Play ();
}
}
Got it working now, by adding
leaveArea = false;
to the Update method.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EX2BoundaryDetect : MonoBehaviour {
// create a GameObject to represent the player
public GameObject playerObject;
public bool leaveArea = false;
// create an Audio-clip object. This assumes we drag a sound file onto the myclip box in the Inspector.
public AudioClip myclip;
// Use this for initialization
void Start () {
// associate playerObject with the player. This assumes the First Person Controller is name "player
playerObject = GameObject.Find ("player");
// get the actual Sound file from the Inspector
GetComponent<AudioSource>().clip = myclip;
}
// Update is called once per frame
void Update () {
PlayAudio1();
if (leaveArea) {
GetComponent<AudioSource> ().Play ();
}
leaveArea = false;
}
public void PlayAudio1 () {
// play the sound if the player is outside some boundaries
if (transform.position.x > 10) {
leaveArea = true;
}
if (transform.position.x < -29) {
leaveArea = true;
}
if (transform.position.z > 10) {
leaveArea = true;
}
if (transform.position.z < -29) {
leaveArea = true;
}
}
}
I think the above answers still do not solve your problem of "When the player steps outside the boundary, a sound will play once."
I will share a cleaner way of doing it (possibly optimized)
Using Bounds
Create our own bounds by using Bounds https://docs.unity3d.com/ScriptReference/Bounds.html
The constructor of Bounds is Bounds(Vector3 center,vector3 size)
So in your case center will be center = (-9.5f, 0, -9.5f) (midpoint formula) and finally the size of the bounding box will be size = (39.0f, 0f, 39.0f)
Let's move to the Code Part
public class BoundsCheck: MonoBehaviour
{
public bool isInside = false;
public bool isPlayedOnce = false;
private Bounds bounds;
void Start()
{
bounds = new Bounds(new Vector3(-9.5f, 0, -9.5f), new Vector3(39.0f, 0f, 39.0f));
}
void Update()
{
CheckBounds();// play the sound if the player is outside some boundaries
if (!isInside &&!isPlayedOnce)
{
Debug.Log("PLAY");
isPlayedOnce = true;
}
}
private void CheckBounds()
{
bool isInsideBound = bounds.Contains(transform.position);
if (isInsideBound)
{
isInside = true;
if (isPlayedOnce)
{
isPlayedOnce = false;
}
}
else
{
isInside = false;
}
}
}
So instead of multiple ifs, we can just check if the position of the transform is inside the bound by using bool isInsideBound = bounds.Contains(transform.position);
Note:- To play sound only once, I have used one more boolean isPlayedOnce
I am not sure if this the most optimized way of doing it. But surely a cleaner way(via code).
This question already has answers here:
How to make the script wait/sleep in a simple way in unity
(7 answers)
Closed 4 years ago.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GateControl : MonoBehaviour
{
public Transform door;
public float doorSpeed = 1.0f;
public bool randomDoorSpeed = false;
[Range(0.3f, 10)]
public float randomSpeedRange;
private Vector3 originalDoorPosition;
// Use this for initialization
void Start()
{
originalDoorPosition = door.position;
}
// Update is called once per frame
void Update()
{
if (randomDoorSpeed == true && randomSpeedRange > 0.3f)
{
StartCoroutine(DoorSpeedWaitForSeconds());
}
door.position = Vector3.Lerp(originalDoorPosition,
new Vector3(originalDoorPosition.x, originalDoorPosition.y, 64f),
Mathf.PingPong(Time.time * doorSpeed, 1.0f));
}
IEnumerator DoorSpeedWaitForSeconds()
{
doorSpeed = Random.Range(0.3f, randomSpeedRange);
yield return new WaitForSeconds(3);
}
}
Making StartCoroutine inside the Update is a bad idea. But I want that it will take one random speed when running the game then will wait 3 seconds and change to a new random speed then wait another 3 seconds and change for another new random speed and so on.
And while it's waiting 3 seconds to keep the current speed constant until the next change.
Update:
This is what I tried:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GateControl : MonoBehaviour
{
public Transform door;
public float doorSpeed = 1.0f;
public bool randomDoorSpeed = false;
public bool IsGameRunning = false;
[Range(0.3f, 10)]
public float randomSpeedRange;
private Vector3 originalDoorPosition;
// Use this for initialization
void Start()
{
IsGameRunning = true;
originalDoorPosition = door.position;
StartCoroutine(DoorSpeedWaitForSeconds());
}
// Update is called once per frame
void Update()
{
door.position = Vector3.Lerp(originalDoorPosition,
new Vector3(originalDoorPosition.x, originalDoorPosition.y, 64f),
Mathf.PingPong(Time.time * doorSpeed, 1.0f));
}
IEnumerator DoorSpeedWaitForSeconds()
{
var delay = new WaitForSeconds(3);//define ONCE to avoid memory leak
while (IsGameRunning)
{
if (randomDoorSpeed == true && randomSpeedRange > 0.3f)
doorSpeed = Random.Range(0.3f, randomSpeedRange);
yield return delay;
}
}
}
But there are two problems.
The first problem is that every 3 seconds, when it's changing the speed of the door, it's also changing the door position from its current position. So it looks like the door position is jumping to another position and then continue from there. How can I make that it will change the speed meanwhile the door keep moving from its current position ?
Second problem is how can I change the randomDorrSpeed flag so it will take effect while the game is running? I Want that if randomDorrSpeed is false use the original speed of the door (1.0) and if it`s true use the random speed.
You already know that the coroutine should start from Start:
void Start()
{
//initialization
StartCoroutine(DoorSpeedWaitForSeconds());
}
So make the coroutine a loop with the proper terminate condition:
IEnumerator DoorSpeedWaitForSeconds()
{
var delay = new WaitForSeconds(3);//define ONCE to avoid memory leak
while(IsGameRunning)
{
if(randomDoorSpeed == true && randomSpeedRange > 0.3f)
doorSpeed = Random.Range(0.3f, randomSpeedRange);
if(!randomDoorSpeed)
doorSpeed = 1;//reset back to original value
yield return delay;//wait
}
}
For the other question you asked, if you think about it you can't possibly use ping pong with dynamic speed based on Time.time. You need to change it like this:
bool isRising = true;
float fraq = 0;
void Update()
{
if (isRising)
fraq += Time.deltaTime * doorSpeed;
else
fraq -= Time.deltaTime * doorSpeed;
if (fraq >= 1)
isRising = false;
if (fraq <= 0)
isRising = true;
fraq = Mathf.Clamp(fraq, 0, 1);
door.position = Vector3.Lerp(originalDoorPosition,
new Vector3(originalDoorPosition.x, originalDoorPosition.y, 64f),
fraq);
}
You can solve the original problem without coroutines:
public float timeBetweenChangeSpeed = 3f;
public float timer = 0;
void Update ()
{
// Add the time since Update was last called to the timer.
timer += Time.deltaTime;
// If 3 seconds passed, time to change speed
if(timer >= timeBetweenChangeSpeed)
{
timer = 0f;
//Here you call the function to change the random Speed (or you can place the logic directly)
ChangeRandomSpeed();
}
}
And about opening and closing doors. Here is a script I used to control doors in a maze game I worked in:
You need to set empty gameObjects with to set the boundaries, that is until what point you want to move the door one opening or when closing. You place this empty gameobjects in your scene and link them to the scrip in the correct field. The script will take the transform.position component on it's own. There is also a trigger enter to activate the door when a character approaches. If you dont need that part, I can edit the code tomorrow.
You can use this script also to move platforms, enemies... in general anything which can move in a straight line.
using UnityEngine;
using System.Collections;
public class OpenDoor : MonoBehaviour {
// define the possible states through an enumeration
public enum motionDirections {Left,Right};
// store the state
public motionDirections motionState = motionDirections.Left;
//Variables for State Machine
bool mOpening = false;
bool mClosing = false;
//bool mOpened = false;
//OpenRanges to open/close the door
public int OpenRange = 5;
public GameObject StopIn;
public GameObject StartIn;
//Variables for Movement
float SpeedDoor = 8f;
float MoveTime = 0f;
int CounterDetections = 0;
void Update () {
// if beyond MoveTime, and triggered, perform movement
if (mOpening || mClosing) {/*Time.time >= MoveTime && */
Movement();
}
}
void Movement()
{
if(mOpening)
{
transform.position = Vector3.MoveTowards(transform.position, StopIn.transform.position, SpeedDoor * Time.deltaTime);
if(Vector3.Distance(transform.position, StopIn.transform.position) <= 0)
mOpening = false;
}else{ //This means it is closing
transform.position = Vector3.MoveTowards(transform.position, StartIn.transform.position, SpeedDoor * Time.deltaTime);
if(Vector3.Distance(transform.position, StartIn.transform.position) <= 0)
mClosing = false;
}
}
// To decide if door should be opened or be closed
void OnTriggerEnter(Collider Other)
{
print("Tag: "+Other.gameObject.tag);
if(Other.gameObject.tag == "Enemy" || Other.gameObject.tag == "Player" || Other.gameObject.tag == "Elevator")
{
CounterDetections++;
if(!mOpening)
Opening();
}
}
void OnTriggerStay(Collider Other)
{
if(Other.gameObject.tag == "Elevator")
{
if(!mOpening)
Opening();
}
}
void OnTriggerExit(Collider Other)
{
if(Other.gameObject.tag == "Enemy" || Other.gameObject.tag == "Player")
{
CounterDetections--;
if(CounterDetections<1)
Closing();
}
}
void Opening()
{
mOpening = true;
mClosing = false;
}
void Closing()
{
mClosing = true;
mOpening = false;
}
}
Using timer and setting an interval. The delegate event will fire every time the interval is reached.
var t = new Timer {Interval = 3000};
t.Elapsed += (sender, args) => { /* code here */};