- Home /
Play sound when enemy is visible on the screen?
Hi, I know this question has been asked a thousand times already but the scripts given in the answers don't work like I want them to...
I know Renderer.IsVisible and other things do trigger something when an enemy is visible but if the enemy is behind a wall and you look at that wall it is still counting as visible which I don't want.
Basicly I want to make a jumpscare just like in the Slender game when you look at him. (No I'm not making a Slender game!)
I have made a script ( Not entirely made by me, just copied and pasted some codes from random sites I found and mixed them together to make it do what it does now :p BTW I'm next to nothing at scripting so please make the answer as simple as possible :-) ) I posted here that plays a sound when the enemy is in the middle of the screen but I want the sound to play when the enemy is visible from anywhere on the screen.
In short:
Is someone able to edit my script so it plays the sound when an enemy is visible anywhere on my screen but it doesn't play the sound when the enemy is behind a wall?
This is my script:
var jumpscareSound: AudioClip; // Sound that plays when enemy is in the middle of the screen
var interval:int; // Interval = X seconds before the sound can be played again if enemy is in the middle of the screen.
private var onetime = false; // If true, interval is busy.
function Update() {
var hit: RaycastHit;
var forward = transform.TransformDirection (Vector3.forward );
if (Physics.Raycast (transform.position, forward, hit))
if(hit.collider.CompareTag("Enemy")){
Debug.Log("Enemy in middle of screen, playing sound now!");
if (!onetime)
{
audio.PlayOneShot(jumpscareSound);
onetime = true;
soundInterval();
}
}else{
Debug.Log("No enemies in the middle of your screen :)");
}
Debug.DrawLine (transform.position, hit.point,Color.white);
}
function soundInterval() {
yield WaitForSeconds(interval);
onetime = false;
}
Thanks!
Your code looks fine to me. You correctly check if the collider you hit is tagged as enemy. $$anonymous$$aybe your wall does not have a collider.
On a side note: transform.TransformDirection (Vector3.forward ) does the same as transform.forward. No need to write that much.
The walls do have colliders, but that's not the problem. Basicly the script works fine but the enemy has to be exactly in the middle of the screen before the ray hits it. How to edit my script so it plays the sound when the enemy is visible from anywhere on the screen like in Slender? I need something like Renderer.IsVisible but with the ability to 'not' see trough walls.. I don't think raycasting is the right choice to do that because it would cost alot of CPU power (if it is even possible). Oh and thanks for the side note :-)
Thanks for the response though :-)
By the way, I hope I'm clear enough with this reply because English isn't my primary language. I'm from the Netherlands :-P
How far away are the enemies jumping out at you from? As long as it's real close I can recommend something. Give me a range that you're trying to check within and I'll take a look at your script.
Answer by iwaldrop · Jan 16, 2013 at 12:15 AM
I would give this a shot. It would require attaching a sphere collider to your camera/player, setting it as a trigger, and setting it's radius to the distance that you want to check within. Essentially, it tracks enemies within the trigger range and casts a ray to them each frame. Whenever it does detect that it hits an enemy it fires a message to it and removes it from the list. You can comment out the list removal and handle a timer on the enemy side if you want.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class EnemyChecker : MonoBehaviour
{
private List<GameObject> enemies = new List<GameObject>();
void OnTriggerEnter(Collider other)
{
if (other.tag == "Enemy")
enemies.Add(other.gameObject);
}
void OnTriggerExit(Collider other)
{
if (other.tag == "Enemy")
enemies.Remove(other.gameObject);
}
void Update()
{
RaycastHit hitInfo;
foreach (GameObject enemy in enemies)
{
Ray ray = new Ray(transform.position, transform.position - enemy.transform.position);
if (Physics.Raycast(ray, out hitInfo))
{
enemy.SendMessage("OnVisible", SendMessageOptions.DontRequireReceiver);
enemies.Remove(enemy.gameObject);
}
}
}
}
Alright thanks, Ill give it a shot tomorrow :-) I'm going to bed now
By the way, you say that if the ray hits an enemy it will display a message and then it deletes the enemy. Am I correct? If so, wouldn't that script do exactly the same thing as my script but with the ability to set a range and delete the enemy if detected? And does it only detect an enemy if it is in the camera's sight? I'm sorry if I'm incorrect or not clear enough.
Your script casts a ray directly ahead of the camera/player (whatever the script is attached to). The script I posted has a list of all enemies in range and casts a ray between the player/camera in the direction of the enemy. The line that says 'enemies.Remove(enemy.gameObject)' will remove it from the list but not destroy or remove your enemy from the scene.
You should implement the behavior that you desire the enemy to have on the enemy Game Object. Thanks! Let me know how it worked out for you!
Will do! I forget alot of stuff but I will try my best to remember to give feedback!
AgentParsec could save us alot of time and trouble by sharing his scripts with us :D
I have attached the script to my main camera in the scene, but there aren't any options available in the expector? I never work with CS scripts so if I'm doing something wrong I'm sorry about that. :(
I did attached a Sphere to my FPSController and set the collider to IsTrigger. I also increased the radius (range) of the Sphere like you said.
Well you're not going to need the public variables you had before. You're going to want a separate script that you place on enemies for that. In that script just make sure you have an "OnVisible" method that will play the sound.