Having problems with OnBecameVisible (sees through walls and is visible on scene view) - c#

I'm trying to make a script that has an enemy chase the player only if the enemy is viewable by the player camera and the player hits the space key. I've been trying to use render.isVisible but run in to two MAJOR problems:
isVisible is enabled even if the enemy is visible in the scene view, making testing impossible.
isVisible works through walls, so if the player is looking at a wall and the enemy is behind it, it still registers as isVisible.
Please help I'm losing my mind. Thank you!
public NavMeshAgent enemy;
public Transform player;
Renderer m_Renderer;
private void Start()
{
m_Renderer = GetComponent<Renderer>();
}
private void OnBecomeInvisible()
{
enabled = false;
}
void OnBecameVisible()
{
enabled = true;
if (Input.GetKey(KeyCode.Space) && m_Renderer.isVisible)
{
Debug.Log("is visible");
enemy.SetDestination(player.position);
}
}
private void Update()
{
OnBecameVisible();
}
I'm honestly not sure what to try, thank you so much for any help!

IsVisible is really not designed for that usage. It just means object is being rendered by any camera. See the documentation here: https://docs.unity3d.com/ScriptReference/Renderer-isVisible.html
To determine whether something is actually visible from one entity by another, you typically have to do a frustum check followed by one or more raycasts to determine whether the target is blocked.

Related

Why my player is invisible, when he dies?

I'm beginner in Unity. I'm making a game in Unity 2D. In this game I have a player, platforms and a die_zone, but when my player die his sprite becomes invisible. How can I change my script to make the sprite visible?
Here is the script:
using UnityEngine;
public class Death : MonoBehaviour
{
public GameObject Respawn;
public Sprite Player_;
public GameObject Player;
public GameObject die_zone1;
public GameObject die_zone2;
public GameObject die_zone3;
public GameObject die_zone4;
public void die()
{
Player.transform.position = Respawn.transform.position;
Player.GetComponent<SpriteRenderer>().sprite = Player_;
}
void OnTriggerEnter2D(Collider2D deth)
{
if (die_zone1.tag == "Death" || die_zone2.tag == "Death" || die_zone3.tag == "Death" || die_zone4.tag == "Death")
{
die();
}
}
}
I will glad to any suggestion.
Thanks!
Let's break your code down to walk through its points of failure.
using UnityEngine;
public class Death : MonoBehaviour
{
public GameObject Respawn;
public Sprite Player_;
public GameObject Player;
public GameObject die_zone1;
public GameObject die_zone2;
public GameObject die_zone3;
public GameObject die_zone4;
Type/field declarations, probably not your problem
public void die()
{
Player.transform.position = Respawn.transform.position;
Player.GetComponent<SpriteRenderer>().sprite = Player_;
}
Suspect, as your bug happens when you die. But maybe there's other code executing?
void OnTriggerEnter2D(Collider2D deth)
{
if (die_zone1.tag == "Death" || die_zone2.tag == "Death" || die_zone3.tag == "Death" || die_zone4.tag == "Death")
{
die();
}
}
}
Ah, looks safe enough. There's a conditional invocation to die(). Presumably your code could crash in the conditional (diezonetag == ...), but that would abort further execution without having edited the Player object. So probably okay.
Alright, so that leaves us with die(). There are two lines, each is a point of failure. They seem to be independent changes of each other (move the player, change their sprite) so perhaps you can test each of them in isolation to determine your culprit. You could do this by commenting out one, running, and seeing if your game still breaks. If that works, then comment out the other (and uncomment the first), run, and hopefully your game breaks.
Player.transform.position = Respawn.transform.position;
Hm, so what is the value of Respawn.transform.position? If that's off-screen or invalid, one would suspect that'd make your player position offscreen or invalid.
You can debug this one by looking at your scene view before/after your Player has died. What's their position before / after?
Player.GetComponent<SpriteRenderer>().sprite = Player_;
What's Player_ set to? Is it, perhaps, null? Alternatively, if you changed your player's sprite to be its death-state sprite in-editor, do you see anything? Maybe your death sprite is fully transparent, or the combination of your death sprite and your spriterenderer's settings makes it not appear on your screen?
When you click on your player object, does the sprite field appear in the inspector, and is it set to something sane?
Actually, you're setting Sprite to a GameObject. How's that supposed to work? Are you setting Sprite to a GameObject containing your sprite, instead of a Sprite itself? This doesn't seem like it should compile. According to Unity's documentation (which I got to by googling unity spriterenderer sprite) here https://docs.unity3d.com/ScriptReference/SpriteRenderer.html the type of SpriteRenderer.sprite is a Sprite, whereas you have a GameObject. Something seems wrong.
Remove this line, or check the sprite of Player_. Also double check if he is invisible or just moved back to the spawn point.
Player.GetComponent<SpriteRenderer>().sprite = Player_;

Detecting collisions between two separate animations

My animations enters a state and it's collision with enemy projectiles either defends himself or gets hurt depending on what animation he is currently in. I'm trying to detect collisions with the ONTRIGGERENTER function and boxcollider2D's but it's not having any affect. I want to figure out how to correctly facilitate trigger enters and collisions between these animations.
I've already tried giving my sprite a tag and calling that tag when the ONTRIGGERENTER function is called but it didn't work. I also tried a more complicated way of calling the tag of the collider but that didn't work either. How do you access the trigger when it's an animation?
string DefenceAnimTag = "Defending";
string DestroyEnemTag = "Eliminated";
//This code is connected to the enemy projectile and trying to
//sense when it's collided with the player
void OnTriggerEnter(Collider2D col)
{
if (col.tag == Defending)
{
GetComponent<Animator>().SetBool("Elim", true);
}
else { //deal damage to the player }
}
//The first method didn't work so I tried a second method.
//Here is an alternative attempt at detecting triggers in
//animations.
void OnCollisionStay2D(Collider2D col)
{
if (col.gameobject.CompareString("Defending"))
{
GetComponent<Animator>().SetBool("Elim", true);
}
}
//This method didn't work either even though the Animation
//WOULD be Defending
I expected enemy projectiles to collide with my player when he was defending himself and get defeated. I knew that it was working when the Enemy projectiles transition into their Elim state, where they get defeated by enemy defenses, however they made collisions and then continued unaffected.
Okay, okay, I figured it out. Because a Gameobject can have many animations to it, you cannot go by the tag that the GameObject in the inspector has. You have to go by the title of the Animations that is currently playing. In order to access the animation currently playing we must use the following code:
AnimatorClipInfo[] m_AnimClipInf;
string m_ClipName;
void Start()
{
//Set up our projectile for possible Elimination
//upon Collision
Getcomponent<Animator>().SetBool("Elim", false);
}
void OnTriggerEnter2D(Collider2D col)
{
m_AnimClipInf = col.GetComponent<Animator>
().GetCurrentAnimatorClipInfo(0);
m_ClipName = m_AnimClipInf[0].clip.name;
if (m_ClipName == "Defending")
{
GetComonent<Animator>().SetBool("Elim", true);
//Projectile gets eliminated
}
}

OnBecameVisible() not call when gameObjects is on camera's field / UNITY

i want to optimise my mobile game by not showing gameObjects that are not in the camera's field. I can't do Occlusion Culling because those gameObjects are instantiated and not static.
So i used
void OnBecameInvisible(){ Renderer.enabled = false; }
void OnBecameVisible(){ Renderer.enabled = true; }
It worked but sometimes, objects remain invisible.
I tried to use:
void Update()
{
if (m_Renderer.isVisible)
{
m_Renderer.enabled = true;
Debug.Log("show");
}
else m_Renderer.enabled = false; Debug.Log("not show");
}
But the performance drops badly.
How could i fix that?
Thank you. Regards.
Unity automatically uses Frustum Culling by default and doesn't render what the camera isn't looking at. Thus this is automatically implemented

Unity Networking: can't spawn scene objects on all clients

I can't really figure out how to solve my problem. I have been looking for an answer but I couldn't find anything.
I have a button in my scene that can be pressed both by client and host. When the button is pressed, it creates a cube in the scene. The problem is that: the cube can be created only by the host and the host is the only user that can see it and manipulate it.
My code is:
public class CreateCube : NetworkBehaviour {
GameObject cubo;
float lastCollisionTime=0;
float collisionTime=0;
void OnCollisionExit(Collision other) {
collisionTime = Time.time;
if (collisionTime - lastCollisionTime >1.5) {
CmdCreaCubo ();
lastCollisionTime = collisionTime;
}
}
}
}
[Command]
void CmdCreaCubo(){
GameObject cubo=Instantiate(Resources.Load("MyPrefabs\\Oggetti\\CubeGrasp")) as GameObject;
cubo.transform.position = new Vector3 (-5.88f, 7.51f, -19f);
cubo.name = "CubeGrasp";
NetworkServer.Spawn (cubo);
}
}
Could anyone help me please?
Thank you so much
Instead using simple Instantiate you should need to use Network.Instantiate
The given prefab will be instanted on all clients in the game.
Synchronization is automatically set up so there is no extra work
involved.

Detect Collision for an instantly refreshed object

so i have an old code for a "Connect4" game it was written years ago, now i am having a big problem getting it results and rebuild them for a unity3D project.
the problem is that every gameObject (i've managed to instanciate in the scene) is, meant to be destroyed and reinstantiated every frame (and i have the feeling that is really more that a frame time); wanting to get the color of each gameobject in time seem to be really challenging, i am supposed now to not enter the code created i am only supposed to get the information from what i get as graphical results.
so now i have a board of boxes having a grid disposition that changes colors according to the player turns (red for the cp and yellow for the plyer).
i created a fixed boxes having colliders and wanted to get the game objects colliding with it everyframe but i failed .
PS: i tested this code and every solution i found in this community hope to find somehelp, thank you.
using UnityEngine;
using System.Collections;
public class SelectorCode : MonoBehaviour
{
public Collision other;
public GameObject GO;
void OnTriggerEnter(Collider other)
{
GO = other.gameObject;
}
void OnTriggerStay(Collider other)
{
GO = other.gameObject;
}
void OnTriggerExit(Collider other)
{
GO = other.gameObject;
}
void Update()
{
GO = this.other.gameObject;
}
}
First make sure the object to which the SelectorCode component is attached has a trigger collider (property "Is Trigger" is checked).
Next you'll get an error in the Updatemethod with GO = this.other.gameObject; since other is never assigned. I think you should remove that line.
Finally, in OnTriggerExit you put in GO the object that is leaving your collider, that doesn't make sense, you should probably assign GO to null at this point :
void OnTriggerExit(Collider other)
{
if (other.gameObject == GO)
{
GO = null;
}
}

Categories