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.
Related
Either the script is outdated, or it's not what I need, but I cannot find an answer to this.
To start off, I'm making a pinball styled game, whenever the ball hits a piece, it changes color, but I have multiple colored balls, and I want to lock the color in place as to not have the other balls change them (to make the game a little bit easier). I've provided a script, which may be a little too complex for a simple solution. The problem area is at the bottom with void FixedUpdate.
(I just wanna change a tag ): )
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ColorBlue : MonoBehaviour
{
public Material mat;
public string ballTag;
public bool reset = false;
public bool found = false;
public void OnCollisionEnter (Collision collisionInfo)
{
if (collisionInfo.collider.tag == "Ball" )
{
gameObject.GetComponent<MeshRenderer>().material.color = Color.blue;
reset = true;
}
}
public void FixedUpdate ()
{
if(reset)
{
GameObject.FindWithTag("Ball");
} found = true;
if(found)
{
GameObject.FindWithTag("Ball").tag = "Untagged";
}
}
}
Instead of searching for the GameObject with the "Ball" Tag which you probably have multiple off in your scene. You can rather just change the tag directly when the collision happens.
Because in the OnCollisionEnter Function you have a reference to the gameObject already, you can just use that to change the tag with collisionInfo.gameObject.tag = "Untagged".
public void OnCollisionEnter (Collision collisionInfo) {
if (collisionInfo.gameObject.CompareTag("Ball") && gameObject.CompareTag("Ball")) {
// Get Mesh Renderer of the Colided Ball Component.
var meshRenderer = collsionInfo.gameObject
.GetComponent<MeshRenderer>();
// Change Color of collided ball to be the same as the ball it collided with.
meshRenderer.material.color = gameObject
.GetComponent<MeshRenderer>().material.color;
// Set Tag to "Untagged" to make sure ball won't change color anymore
colliderInfo.gameObject.tag = "Untagged";
}
}
You could also add additional Code to change the color depending on the current Color of the gameObject. Additionaly I would advise you to use CompareTag(), which checks if the tag even exists in your scene.
If you want to get the collided gameObject you can do that with collisionInfo.gameObject.tag
I have recently started to learn how to code and I am really enjoying it, I am little stuck and I'd like to have your help. I have added:
A plane
Character Controller (Named 'Matt' in Hierarchy)
A Cube (Which should change color to Red on keypress and also if
Character Controller collides with the collider on cube) + The script
is attached to the cube
I would like the CUBE to change it's color if R key is pressed (which works) or if the player controller collides with the cube's collider.
Screenshot of my scene below
using UnityEngine;
using System.Collections;
public class colorChange : MonoBehaviour
{
public GameObject cube;
private Renderer rend;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
// This will get the OBJECT to CHANGE COLOR on KEY PRESS
if (Input.GetKeyDown (KeyCode.R))
GetComponent<Renderer> ().material.color = Color.red;
print ("A Key Pressed For Red Color");
}
void OnCollisionEnter (Collision col)
{
if (col.collider.name == "Matt")
{
rend.material.color = Color.yellow;
}
}
}
Here is a screenshot of the properties on the the two objects:
The complication in your collision detection is that you're using a Character Controller, which doesn't exactly work within Unity's physics simulation. As a result OnCollisionEnter() will never be called during a collision between a Character Controller and a normal collider.
It sounds like what you need is the OnControllerColliderHit() method. As per the documentation:
OnControllerColliderHit is called when the controller hits a collider while performing a Move.
However, note that it's the Character Controller that receives the event, and not the object it bumped into. So if you do revise your code to use this, you'll need to put the event on the GameObject with the controller, and detect/change the cube's renderer colour from there:
void OnControllerColliderHit(ControllerColliderHit col) {
if (col.collider.name == "cube")
{
col.gameObject.GetComponent<Renderer>().material.color = Color.yellow;
}
}
Note: Because of all the physics-related headaches associated with using Unity's Character Controller, you may actually want to create your own version of it using a Rigidbody and a capsule collider. It will take a bit more scripting, but the solution Unity offers really doesn't work well with other parts of the engine.
Hope this helps! Let me know if you have any questions.
First if you are going to detect collision then your collider on cube shouldn't be trigger. If you are going to use it as a trigger then you should use OnTriggerEnter method. Anyway attach to the character controller another collider like sphere collider make sure it's not trigger and you are good. Use GetComponent() something like this:
void OnCollisionEnter(Collision col)
{
if (col.gameObject.tag == "Player")
{
GetComponent<Renderer>().material.color = Color.yellow;
}
}
You need to use OnTriggerEnter instead of OnCollisionEnter
Cause your cube not really solid (cause you enabled trigger boolean in the box collider)
void OnTriggerEnter(Collider other)
{
if(other.name=="Cube")
{
transform.parent.GetComponent<Renderer>().material.color = Color.red;
}
}
also try to use Debug.Log in a lot of places to make sure you are executing or not.
That might do it.
UPDATE:
About the rend variable, since you have it private you need to assign it before executing the color changing, you'll get a NullReferenceException cause it's not assigned (the rend var)
Either make it public and assign in the inspector or do it in the Start():
rend = GetComponent<Renderer>();
Okay guys, I have managed to make it work. Below is my final code:
using UnityEngine;
using System.Collections;
public class colorChange : MonoBehaviour {
public Material color002;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
// This will get the OBJECT to CHANGE COLOR on KEY PRESS
if (Input.GetKeyDown (KeyCode.R)) {
GetComponent<Renderer> ().material.color = Color.red;
Debug.Log ("R Key Press For RED");
// This will get the OBJECT to CHANGE MATERIAL on KEY PRESS
} else if (Input.GetKeyDown (KeyCode.P)) {
GetComponent<Renderer> ().material = color002;
Debug.Log ("P Key Press For Pink Material (color002)");
}
}
// This will get the OBJECT to CHANGE COLOR if the FPS Controller collides with Cube GameObject
void OnTriggerEnter(Collider other)
{
print (other.name);
if(other.name=="FPSController")
{
GetComponent<Renderer>().material.color = Color.green;
Debug.Log ("FPS Collided with CUBE");
}
}
}
Thanks a lot for your help! Time to keep on coding :D
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
I'm having an issue where I can't disable a script from the other script - they are both public and within the same package (I think).
Here is my code for the script I'm trying to disable from:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
#if UNITY_EDITOR
using UnityEditor;
#endif
using RTS;
public class PauseMenu : MonoBehaviour {
Canvas canvas;
private Player player;
public Button Button2;
void Start()
{
Debug.Log ("asdf");
player = transform.root.GetComponent< Player >();
canvas = GetComponent<Canvas>();
canvas.enabled = false;
ResourceManager.MenuOpen = false;
Button2.GetComponent<Button>().onClick.AddListener(() => { Resume();});
if(player) player.GetComponent< UserInput >().enabled = false;
}
And the code for the other script:
//sets up what resources we are using
using UnityEngine;
using System.Collections;
using RTS;
public class UserInput : MonoBehaviour {
//sets up a private variable for only this class - our player
private Player player;
// Use this for initialization
void Start () {
//this goes to the root of the player ie the object player and allows us to
player = transform.root.GetComponent< Player > ();
}//end Start()
So the part that is not working is:
if(player) player.GetComponent< UserInput >().enabled = false;
And the code runs and then causes the runtime error:
NullReferenceException: Object reference not set to an instance of an object
PauseMenu.Pause () (at Assets/Menu/PauseMenu.cs:40)
PauseMenu.Update () (at Assets/Menu/PauseMenu.cs:29)
Here is a picture showing my scene hierarchy and components:
The issue here is that you try to execute transform.root.GetComponent< Player >(); from within PauseMenu, which is on the "Canvas" object.
The problem with that is that the topmost transform in the hierarchy of your "Canvas" object (which is what transform.root returns) is, well, the transform of the "Canvas" object - which is in no way related to the UserInput script you are trying to access. For this script to actually work, you would need the transform of your "Player" object, which is the object that actually has the UserInput script.
My suggestion is to eliminate the need to run GetComponent() at all - create a public UserInput variable in your PauseMenu class, then (while selecting your "Canvas") in the editor, drag the "Player" object into that new field. This will cause the UserInput script of your "Player" object to be accessible within the PauseMenu.
So your PauseMenu script might look like:
public class PauseMenu : MonoBehaviour {
Canvas canvas;
public UserInput playerInput; // Drag the Player object into this field in the editor
public Button Button2;
void Start()
{
Debug.Log ("asdf");
canvas = GetComponent<Canvas>();
canvas.enabled = false;
ResourceManager.MenuOpen = false;
Button2.GetComponent<Button>().onClick.AddListener(() => { Resume();});
playerInput.enabled = false;
}
}
Hope this helps! Let me know if you have any questions.
(An alternative is to use GameObject.Find("Player") to get GameObject of "Player". This needs a bit more code but doesn't use the editor.)
I would say your player = transform.root.GetComponent< Player >(); arrives null.
So you are trying to disable something that doesnt exist.
Enter debug mode and see if your player is null or not.
I am having an issue respawning a prefab after it has been destroyed. I can't seem to get it to respawn back at its original start position after a second of being destroyed. I have created an empty game object and attached the SpawnTargets.cs script to it. I'm not sure of what the best methodology to approach this situation. Another object with a script attached to it does the actual destroy of the prefab. BulletCollisionHandler.cs works fine though. Thanks for any help. Code is below:
SpawnTargets.cs:
using UnityEngine;
using System.Collections;
public class SpawnTargets : MonoBehaviour
{
public GameObject targetCircle;
public GameObject targetSquare;
public GameObject targetStar;
private Vector3 circleSpawnPosition = new Vector3(0.0f, 1.227389f, -7.5f);
private Vector3 squareSpawnPosition = new Vector3(0.0f, 1.027975f, -7.993299f);
private Vector3 starSpawnPosition = new Vector3(0.0f, 1.8f, -7f);
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
SpawnTarget ();
}
void SpawnTarget()
{
}
}
BulletCollisionHandler.cs:
using UnityEngine;
using System.Collections;
public class BulletCollisionHandler : MonoBehaviour
{
public GameObject targetCircle;
// Use this for initialization
void Start ()
{
Destroy (gameObject, 2);
}
// Update is called once per frame
void Update ()
{
}
void OnCollisionEnter(Collision other)
{
if(other.gameObject.name == "TargetSquare")
{
other.gameObject.rigidbody.isKinematic = false;
((TargetMovementHorizontal)other.gameObject.GetComponent<TargetMovementHorizontal>()).enabled = false;
Destroy (other.gameObject, 1);
Debug.Log("Hit square");
}
else if(other.gameObject.name == "TargetCircle")
{
other.gameObject.rigidbody.isKinematic = false;
((TargetMovementHorizontal)other.gameObject.GetComponent<TargetMovementHorizontal>()).enabled = false;
Destroy (other.gameObject, 1);
Debug.Log("Hit circle");
}
else if(other.gameObject.name == "TargetStar")
{
other.gameObject.rigidbody.isKinematic = false;
((TargetMovementHorizontal)other.gameObject.GetComponent<TargetMovementHorizontal>()).enabled = false;
((TargetMovementVertical)other.gameObject.GetComponent<TargetMovementVertical>()).enabled = false;
Destroy (other.gameObject, 1);
Debug.Log("Hit star");
}
}
}
You're not calling Instantiate() anywhere, so it's hard to see where the new object would come from in the code you've supplied.
In any case, it might be better not to use Destroy. If you want to immediately reset the object, why not simply recycle it back to the start position? It's a good idea to avoid instantiating and destroying lots of objects, it's better to hide/disable the ones your don't need and unhide/re-enable them.
Here's a tutorial on the general idea. The tutorial is about groups of objects but the same trick would work for recycling single objects too.
You are better of using gameObject.SetActive( true/false ); for activating / deactivating the gameObject instead of just using Destroy.
Then if you are using Destroy you have 3 options that comes to mind for getting it into the desire position before the Player sees it.
1) You enable the game object after disabling its Renderer component. Then you equalize the transform's position / rotation the one you need. After this you re-enable the Renderer component. It should be placed where you want it.
2) You Instantiate the gameObject, but first making sure the Renderer component is disabled on its Prefab, by default, so you can re-assign its Transform values then - re-enable the Renderer again.
3) You make an invisible gameObject (an Empty gameObject) and Instantiate the wanted gameObject, you then make the Empty to be the parent of the newly created gameObject.. Provided that the parent Empty is exactly where you want it to be, when you instantiate and reset the child's position it should jump off right on top the the Empty parent.
I'm not giving code since you haven't and I don't have no idea of which method you might end up liking more. In terms of performance the Enable/Disable are the best option.
And as theodox says Object Pooling is your best friend for things like bullets, although it might be applied to many other gameObjects that might work as 'collections of objects' on your game's logic. It's totally worth learning.