How to know if a GameObject has a mesh in Unity? - c#

I attached the following script to a GameObject to determine if it is a mesh.
using UnityEngine;
public class MeshCheck : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
var meshChecker = this.GetComponent<MeshRenderer>();
if(meshChecker != null)
{
Debug.Log("this is mesh");
}
else
{
Debug.Log("this is not mesh");
}
}
}
This script seems to work fine as far as I've tried.
However, this method does not seem to be able to determine all meshes.
For example, there is a mesh with a blendShapeds.I opened and looked at the Inspector for that mesh. It seemed that the the mesh have "SkinMeshRenderer" and the mesh didn't have "MeshRenderer". And the above script output "this is not mesh".
The solution to this problem is to modify the script as follows:
using UnityEngine;
public class MeshCheck : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
var meshChecker = this.GetComponent<MeshRenderer>();
var blendShapeChecker = this.GetComponent<SkinnedMeshRenderer>();
if (meshChecker != null || blendShapeChecker != null)
{
Debug.Log("this is mesh");
}
else
{
Debug.Log("this is not mesh");
}
}
}
I'm wondering if the second script solves all the problems.
If anyone knows how to accurately determine all meshes, please let me know.

You can use the Mesh Filter to avoid having all the controls via code.
In this way instead of having
if (meshChecker != null || blendShapeChecker != null || othermeshes...)
You will check
if(MeshFilter.mesh != null)
But with the Mesh Filter you can play with multiple meshes and check between all of them with the Mesh.SubMeshCount or the Mesh.setIndices or even Mesh.CombineMeshes but it's all about the usage you need for the game!

Related

Unity 3D: How could i store and replace a prefab from a grid?

i am creating a video game like Crypt of the necrodancer and i am blocked when i want to generate a map
my idea was simple :
make a grid system and replace some tiles to have specific tiles (obstacle, wall...) but i don't know how i should store the information to replace my tile.
I based my grid generation map from Sebastian Lague tutorial
i would like to replace in the inspector my tiles
as far as i am, i've found a script for replacing some tiles by another but i can't save it...
Here is the script for replacing stuff
using UnityEngine;
using UnityEditor;
public class ReplaceWithPrefab : EditorWindow
{
[SerializeField] private GameObject prefab;
[MenuItem("Tools/Replace With Prefab")]
static void CreateReplaceWithPrefab()
{
EditorWindow.GetWindow<ReplaceWithPrefab>();
}
private void OnGUI()
{
prefab = (GameObject)EditorGUILayout.ObjectField("Prefab", prefab, typeof(GameObject), false);
if (GUILayout.Button("Replace"))
{
var selection = Selection.gameObjects;
for (var i = selection.Length - 1; i >= 0; --i)
{
var selected = selection[i];
var prefabType = PrefabUtility.GetPrefabType(prefab);
GameObject newObject;
if (prefabType == PrefabType.Prefab)
{
newObject = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
}
else
{
newObject = Instantiate(prefab);
newObject.name = prefab.name;
}
if (newObject == null)
{
Debug.LogError("Error instantiating prefab");
break;
}
Undo.RegisterCreatedObjectUndo(newObject, "Replace With Prefabs");
newObject.transform.parent = selected.transform.parent;
newObject.transform.localPosition = selected.transform.localPosition;
newObject.transform.localRotation = selected.transform.localRotation;
newObject.transform.localScale = selected.transform.localScale;
newObject.transform.SetSiblingIndex(selected.transform.GetSiblingIndex());
Undo.DestroyObjectImmediate(selected);
}
}
GUI.enabled = false;
EditorGUILayout.LabelField("Selection count: " + Selection.objects.Length);
}
}
any ideas for how i could save the informations?
Unity recently added a tilemap system a few versions ago. It seems to be what you're looking for and it already handles the grids for you.
You can read more about it here:
https://docs.unity3d.com/Manual/class-Tilemap.html
You can edit the tilemap with the SetTile method and a Tile object, rather than instanciating a bunch of prefabs. The Tiles themselves are created with a tile palette which you can also read more about in the page above.

Why Camera.current returns null when I am in Unity Editor? And is there any other ways to catch the current camera?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteAlways]
public class SkyBox : MonoBehaviour
{
public Material[] skyboxes;
public Camera skyboxCamera;
public float skyboxMoveSpeed = 2f;
private int index = 0;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
SwitchSkybox();
}
if (RenderSettings.skybox == skyboxes[1])
{
RenderSettings.skybox.SetFloat("_Rotation", Time.time * skyboxMoveSpeed);
}
}
public void SwitchSkybox()
{
index++;
if (index == skyboxes.Length)
{
index = 0;
}
RenderSettings.skybox = skyboxes[index];
if (RenderSettings.skybox == skyboxes[1])
{
skyboxCamera.enabled = true;
Camera.current.enabled = false;
Time.timeScale = 1.0f;
}
else
{
skyboxCamera.enabled = false;
Camera.current.enabled = true;
Time.timeScale = 0.0f;
}
}
}
The script switch between skyboxes the default and my skybox and also switch between the currently active camera and the sky box camera.
But when I'm hitting the escape key it's throwing null exception in the editor on the line number 46 :
Camera.current.enabled = false;
The current of the Camera is null
I want to make that when I press the escape key it will switch to my skybox and to the skybox camera and also will pause the game (Later I will make a main menu when the game is paused).
This is the Camera.current, from the manual.
The camera we are currently rendering with.
Also worth noting the comment from Ruzihm.
The Unity engine typically assigns an already-instantiated instance of
Camera to Camera.current
So, from your scripts, I see 2 issues. The one directly related to this questions happens just in editor mode and I will start from that one.
Editor Issue: Camera.current is null
When working in the editor, Camera.current won't be just your own application's camera, but it could be any camera. It could even refer to the editor's scene view camera.
In this last case, if your scene view is not in focus (IE when you've focus on Game Window) Camera.current will be null.
Logical Issue: you couldn't switch back
When you try to switch back from skyboxCamera, your Camera.current will be the same skyboxCamera, and not your default camera. So you won't be able to retrieve the previous camera.
SOLUTION
Do not use Camera.current, but store all of your cameras in your script (this solution is also better for perfomance, since both Camera.current and Camera.Main are not performant scripts).
In your case you will need to add this piece of code to your script and use the EnableSkyBoxCamera method.
public Camera defaultCamera;
public Camera skyBoxCamera;
private Camera _currentCamera;
public void EnableSkyBoxCamera(bool enableSkyBox)
{
defaultCamera.enabled = !enableSkyBox;
skyBoxCamera.enabled = !enableSkyBox;
if (enableSkyBox) _currentCamera = skyBoxCamera;
else _currentCamera = defaultCamera;
}
If camera is null you can't set the enabled to false without getting a nullpointerexception. Instantiate the camera first or remove that line of code.
*** Edit ill take another crack at this
try
Camera.main.enabled = false;
instead of
Camera.current.enabled = false;
As per Unity docs in reference to Camera.current: 'Most of the time you will want to use Camera.main instead. Use this function only when implementing one of the following events: MonoBehaviour.OnRenderImage, MonoBehaviour.OnPreRender, MonoBehaviour.OnPostRender'

Deleting previous added Component of a GameObject

I have this script where it would add the SelectMove script at runtime when a character was touched by the user.
public GameObject target;
void Start () {
}
// Update is called once per frame
void Update () {
if(Input.touchCount > 0 || Input.GetTouch(0).phase == TouchPhase.Began){
ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
Debug.DrawRay(ray.origin,ray.direction * 20,Color.red);
if(Physics.Raycast(ray, out hit,Mathf.Infinity)){
Debug.Log(hit.transform.gameObject.name);
target = hit.transform.gameObject;
//Destroy(hit.transform.gameObject);
selectedPlayer();
}
}
}
void selectedPlayer(){
target.AddComponent(Type.GetType("SelectMove"));
}
In the code above, if the user will click Player A, Player A will move using accelerometer. What I need to do is if I click another character, say Player B, I need Player A to stop moving and it is now Player B's time to move. But I seemed not to get what I want. I tried destroying the script by using Destroy(this) or by this code:
if (target != null)
{
var sphereMesh = target.GetComponent<SelectMove>();
Destroy(sphereMesh);
}
But it is still not working.
If I don't destroy the previous added script, if the user clicks for another character, the previous selected player still moves along with the new one.
Is there another way that I could achieve what I needed to do?
public GameObject target = null;
void Update ()
{
if(Input.touchCount > 0 || Input.GetTouch(0).phase == TouchPhase.Began)
{
Ray ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
Debug.DrawRay(ray.origin,ray.direction * 20,Color.red);
RaycastHit hit;
if(Physics.Raycast(ray, out hit,Mathf.Infinity))
{
Debug.Log(hit.transform.gameObject.name);
if(this.target != null){
SelectMove sm = this.target.GetComponent<SelectMove>()
if(sm != null){ sm.enabled = false; }
}
target = hit.transform.gameObject;
//Destroy(hit.transform.gameObject);
selectedPlayer();
}
}
}
void selectedPlayer(){
SelectMove sm = this.target.GetComponent<SelectMove>();
if(sm == null){
target.AddComponent<SelectMove>();
}
sm.enabled = true;
}
The code reuses your base, the new part is that you use the previous selected object to disable the SelectMove script (I assume it is the one moving things). Instead of destroying it, it enables/disables so you save that memory consumption.
I do not think Adding and destroying scripts is the convenient method here.
Try this:
1. Add the SelectMove script to all movable players.
2. Add a public property bool IsMoving = false; to the SelectMove script and make an if statement to move if IsMoving is true.
3. Change selectedPlayer() method to instead change the target player IsMoving to true, and set the previous one (or simply all other players) to false.

lights gameobjects does not have a light component?

I am a bit stuck with lights management.
I have 4 lights; each with a tag ""lights_hall". In my code, I do assign all these lights to a gameobject list
roomlights = Gameobject.FindGameObjectsWithTag("lights_hall");
I get the list with the gameobjects, which I assume they are lights.
Then I go through each element of the list, to turn them on and off, but I get an error when the script try to retrieve the component "Light".
foreach (GameObject single_light in roomlights)
{
if (single_light.GetComponent<Light>().intensity == 1)
single_light.SetActive(false);
else
single_light.SetActive(true);
}
Unity tell me that there is no light component attached to the gameobject. How is this possible if the light component is part of a light gameobject?
I did check some examples and they all do the same: create a list of gameobjects, use find to get all the lights that has the tag as specified, and then access the light component for each element in the list.
Am I missing something here? I did also try to access each single element light component, so I can use .enable, but it does not appear in auto completion.
EDIT==================================
This is the script that I use; it is attached to a simple cube, which has a collider, so when the first person controller get in the trigger area, and you press "l" on the keyboard, the ligths should turn off.
I did verify the names, and the names are matching the point light game objects in the scene; although Unity print the error "MissingComponentException: There is no "Light" attached to the "switch" game object, but a script is trying to access it. You probably need to add a Light to the game object "switch". Or your script needs to check if the component is attached before using it"
The ligts are point lights; nothing out of the ordinary.
using UnityEngine;
using System.Collections.Generic;
public class LightsSwitch : MonoBehaviour {
private bool istriggered = false;
public GameObject[] roomlights;
// Use this for initialization
void Start () {
roomlights = GameObject.FindGameObjectsWithTag("lights_hall");
foreach (GameObject light in roomlights)
Debug.Log(light.name);
}
// Update is called once per frame
void Update () {
if (istriggered && Input.GetKeyDown(KeyCode.L))
{
foreach (GameObject single_light in roomlights)
{
if (single_light.GetComponent<Light>().intensity == 1)
single_light.SetActive(false);
else
single_light.SetActive(true);
}
}
}
void OnTriggerEnter(Collider world_item)
{
istriggered = true;
Debug.Log("light switch");
}
void OnTriggerExit(Collider world_item)
{
istriggered = false;
Debug.Log("light switch gone");
}
}
A few issues.
First, in your code:
roomlights = Gameobject.FindGameObjectsWithTag("lights_hall");
Make sure to change Gameobject to GameObject.
Now, assuming roomlights is a GameObject[], set your code as follows:
foreach (GameObject single_light in roomlights)
{
if (single_light.GetComponent<Light>().enabled == true)
single_light.SetActive (false);
else
single_light.SetActive (true);
}
My suggestion would be to disable the Light component, rather than the whole GameObject itself. This can be achieved with:
single_light.GetComponent<Light>().enabled = false;
I've setup an example project, this implementation should work for you.
using UnityEngine;
using System.Collections;
public class turnofflight : MonoBehaviour {
public GameObject[] roomlights;
// Use this for initialization
void Start () {
roomlights = GameObject.FindGameObjectsWithTag("light_comp");
foreach (GameObject light in roomlights)
Debug.Log(light.name);
}
// Update is called once per frame
void Update () {
foreach (GameObject single_light in roomlights)
{
if ((single_light.GetComponent<Light>().intensity == 1.0f))
single_light.SetActive(false);
else
single_light.SetActive(true);
}
}
}
I'm having no issues with this implementation.

Grab and drop object

I'm trying new things and I'm stuck to find a way to drag and drop objects. My player is a square and he have a hand attached. Here is an example:
That red thing in the arm is the "hand", when I press shift it turns green. I made the detection like a ground check. Here is the code:
void Update () {
touch = Physics2D.OverlapCircle(touchDetect.position, 0.01f, objectLayer);
mao1.SetBool("Ligado", ligado);
if (Input.GetKey(KeyCode.LeftShift)) {
ligado = true;
} else {
ligado = false;
}
}
The touchDetect is working fine, because he turns to "true" when touches the box:
My question is: I don't know how to put in the script that I want him to grab the object and drop when I want to. If I need to use Raycast, how would the code looks like?
In order to "grab" an object in unity, simply set the transform.parent of the gameobject you wish to grab, to the transform of the gameobject you wish to grab it with.
For example, in your code you are using Physics2D.OverlapCircle which returns a Collider2D object. You can use that collider to grab on to your gameobject.
Collider2D touch = Physics2D.OverlapCircle(touchDetect.position, 0.01f, objectLayer);
if (Input.GetKey(KeyCode.LeftShift) && touch != null)
{
//grab on to the object
touch.gameObject.transform.parent = this.transform;
//if your box has a rigidbody on it,and you want to take direct control of it
//you will want to set the rigidbody iskinematic to true.
GetComponent<Rigidbody2D>().isKinematic = true;
}
else if( touch != null)
{
//let the object go
touch.gameObject.transform.parent = null;
//if your object has a rigidbody be sure to turn kinematic back to false
GetComponent<Rigidbody2D>().isKinematic = false;
}
Just place a GameObject with SprieRender component attach it to hand tip.
Put this script to that qube and follow what I commented
using UnityEngine;
using System.Collections;
public class collid : MonoBehaviour {
// Use this for initialization
public Sprite mySprite; // Put Here that Qube Sprite
public GameObject Cursorimg; // Put the gameobject here from hierarchy
void Start () {
mySprite = GetComponent<SpriteRenderer>().sprite;
}
// Update is called once per frame
void Update () {
if(Collide conditions) {
Debug.Log(" Collide ");
Cursorimg.GetComponent<SpriteRenderer>().sprite = mySprite;
Cursorimg.GetComponent<SpriteRenderer>().sortingOrder = 3;// U change based on your option
}
if(DropCondition)
{
Debug.Log("Drop");
Cursorimg.GetComponent<SpriteRenderer>().sprite =null;
}
}
If this not works Here is a script that gameobject with Sprite will follow mouse position,
Vector3 pos = Input.mousePosition;
pos.z = Cursorimg.transform.position.z - Camera.main.transform.position.z;
Cursorimg.transform.position = Camera.main.ScreenToWorldPoint(pos);
this code follows in update and Cursorimg is Gameobject
I think This would help you, Let me know further

Categories

Resources