Simple way to Delete the Last Child of a GameObject - c#

I'm trying to write a simple script that gets the child count of a GameObject and then destroys the last child (I want it to basically function like a delete key) but I'm getting the error: Can't remove RectTransform because Image (Script) depends on it. Can someone tell me how to resolve this?
using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
public class DeleteSymbol : MonoBehaviour, IPointerClickHandler
{
public GameObject deleteButton;
public GameObject encodePanel;
public GameObject decodePanel;
#region IPointerClickHandler implementation
public void OnPointerClick (PointerEventData eventData)
{
int numChildren = encodePanel.transform.childCount; // get child count
Debug.Log("There are " + numChildren + " children");
if (numChildren > 0)
{
Destroy(encodePanel.transform.GetChild(numChildren - 1)); // destroy last child
}
}
#endregion
}

Solved it with this:
Destroy(encodePanel.transform.GetChild(numChildren - 1).gameObject);

The answer is that you need to destroy the game object itself, but your code tries tried to destroy the transform instead. The transform (and other components) may have dependencies that do not allow them to be destroyed in isolation. Unfortunately Unity provides the same method for destroying components and the game object itself, and an unhelpful error message if you pick wrong.
So the answer:
Destroy(encodePanel.transform.GetChild(numChildren - 1).gameObject);
is correct, and that's why.

Related

How to display Debug.Log messages on Text.UI after restarting the same scene? [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 1 year ago.
I'm working on a simple little game in Unity where the objective is to use a floating hand to guide the ball into the basket and every time the ball enters the basket, the game resets due to an hidden collider with a trigger inside the basket.
The feature I'm trying to implement:
Every time the ball goes into the basket the text.UI updates to reflect your new score, beginning with 0 points and the score increments by 1 for every slam dunk.
The issue:
How do I convert the "Debug.Log" into a text.UI?
I was only successful in updating the score on the Unity console and I wasn't able to convert these events to the text.UI.
The text.UI GameObject I've created only displays the text "New Game" and never gets updated.
Update: I've created a new script to solve this and I got this error:
NullReferenceException: Object reference not set to an instance of an object
ChangingText.Start () (at Assets/Scripts/ChangingText.cs:12)
The process:
1. Creating a GameObject and script to keep data after scene restarts.
I've created a script to keep the score after restarting the the same scene, I have only one scene.
I've attached this script to the game object: "GameController" and that's how was able to keep the score updated.
The name of the scene is:
"DunkingPractice"
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GameControl : MonoBehaviour
{
// Giving it a name called "Control", any other script can interact with it
public static GameControl Control;
public int score;
// Called before Start()
private void Awake()
{
// If there's a control already, delete this
// If there's no control, make this the control object
if (Control == null)
{
Control = this;
DontDestroyOnLoad(gameObject); // Don't destory the object when a scene is loaded
}
else if (Control != this)
{
Destroy(gameObject);
}
}
}
Image that I've included to demonstrate this:
Creating "GameController" GameObject and Script
2. Creating an hidden trigger collider GameObject inside the basket with a scenemanager.loadscene inside the script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class RestartTrigger : MonoBehaviour
{
void OnTriggerEnter2D(Collider2D collision)
{
if (collision.tag == "Ball")
{
SceneManager.LoadScene(0);
}
}
}
Image that I've included to demonstrate this:
Creating a trigger collider and restart trigger
3. Creating a script to Keep score and adding this component to the aforementioned trigger collider
Notice that the script refers to the Game Control script I've created earlier.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class KeepingScore : MonoBehaviour
{
static void OnTriggerEnter2D(Collider2D collision)
{
if(collision.tag == "Ball")
{
GameControl.Control.score++;
if (GameControl.Control.score == 1)
{
Debug.Log("You have " + GameControl.Control.score + " point");
}
else if (GameControl.Control.score != 1)
{
Debug.Log("You have " + GameControl.Control.score + " points");
}
}
}
}
Here's another image that I've included:
Creating a script to keep score and attaching it to the trigger field
4. Creating a Text.UI on screen and creating a new script to change text only for an error to appear
This is the script that produces the NullReferenceException error:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ChangingText : MonoBehaviour
{
public Text scoreText;
void Start()
{
scoreText.text = GameControl.Control.score.ToString();
}
}
Here's another image to demonstrate:
Creating a text object
Here's a screen recording I've made to show how my scene currently looks like:
https://www.screencast.com/t/JUBsUkHuHgHC
Do you have any suggestions?
Thank you
NullReferenceException is happened if one of your instance is null and you are trying to modify it, in the log error, it show that :
Object reference not set to an instance of an object ChangingText.Start ()
It means that your scoreText instance does not connect to any UI and it's null. To resolve that, just simply create text UI gameObject and drag it into the 'scoreText' field in the object that is assigned with ChangingText script

Having trouble creating a duplicate of a game object with input.getkeydown(KeyCode.Space) in C# and Unity

kinda new to coding so help would be appreciated. I'm trying to duplicate this GameObject "cube" in unity and I'm having trouble with it. what im trying to do is duplicate the cube and get it to stack on top of each other over and over.
I know if i got this to work it would duplicte it in the same postion so you would only see it duplicate in the higharchy.
using System.Collections;
using UnityEngine;
public class cube : MonoBehaviour
{
public GameObject cube1;
public void update()
if(input.getKeyDown(KeyCode.Space))
{
instantiate cube1;
}
}
I assume you know the height of the cube, you are working with. In unity the default height is 1.0f(For the primitive cube).
Btw if your code is a pseudo code then its okey but if not, you need more training before writing such scripts, even tho this type of script is extremely easy to write.
(ps: i wrote this script in notepad++ hope it compiles :/)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// We start classes with capital letters in c# its a convention :)
public class Cube : MonoBehaviour
{
// Same applies to public class fields & Properties
// Marking a MonoBehaviour field as public will allow you to directly assign values to it
// inside the editor
public GameObject OriginalCube;
// Same can be achieved with private fields using the serializefield attribute
[SerializeField]
private float cubeHeight = 1.0f;
// In case you would like to store the duplicated cubes
public List<GameObject> Cubes = new List<GameObject>();
private void Awake()
{
// Adding the first cube to the list, i assume your cube is already in the scene
Cubes.Add(OriginalCube);
}
private void Update()
{
if(Input.GetKeyDown(KeyCode.Space))
{
// We instantiate a new cube and add it to the list
Cubes.Add(Instantiate(Cubes[Cubes.Count - 1]);
// We ask the previous cube position (the one we copied)
Vector3 previousCubePosition = Cubes[Cubes.Count - 2].transform.position;
// then we assign a new position to our cube raised by "1 unit" on the y axis which is the up axis in unity
Cubes[Cubes.Count - 1].transform.position =
new Vector3(previousCubePosition.x, previousCubePosition.y + cubeHeight, previousCubePosition.z);
}
}
}
One way you can have your goal achieved, is to add to your newly instantiated object's y position a constant amount. This constant amount will be increased each time you create a new duplicate of your object.
public GameObject cube1;
private int instantiateCounter = 0;
public float PULL_UP_AMOUNT = 30f;
public void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
instantiateCounter++;
GameObject newCube = Instantiate(cube1);
newCube.transform.position = new Vector3(cube1.transform.position.x, cube1.transform.position.y + instantiateCounter * PULL_UP_AMOUNT, cube1.transform.position.z);
}
}
The constant amount we're talking about is PULL_UP_AMOUNT.
Keep in mind, you can access your new duplicate's properties by saving the result of Instantiate method inside a new GameObject, just like I did.

Variables in other scripts in Unity

I am trying to create a game in Unity 2d. I have finished most of what I want to do and have moved on to the enemies. The enemies (dragons) come in from different points of screen. To do this I have placed sprite game objects where I want the dragon to spawn. I have made all of these objects a child of another object called DragonAncores. I attached a script to DragonAncores which says this...
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DragonTracker : MonoBehaviour {
// is gold dragon in play?
public bool GoldDragonInit = false;
// curently active dragons
public int DragonCount = 0;
// defalts to 5
public int Difficulty = 5;
}
I am then attaching a script to each sprite which will eventually summon in a dragon Prefab (containing 2 colliders and an animator) biased of If statment logic derived from the other variables.
Below is the code I am using.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Dragons : MonoBehaviour {
// same as GoldDragonInit
bool GoldDragonSpawn = false;
// same number as DragonCount in DragonTrackeer
int LiveDragons;
// same as Difficulty
int DifLev;
//get cariables from other script
DragonAncors.cs.GetComponent.<DragonTracker>() GoldDragonInit = GoldDragonSpawn;
System.Random RNG= new System.Random();
void update()
{
RSpawn=RNG.Next(0,2)
DragonType=RNG.Next(0,101)
if (RSpawn = 1) ;
{
if (LiveDragons > DifLev) ;
{
if (DragonType > 99) ;
{
// summon regular dragon
}
if (DragonType = 100) ;
{
if (GoldDragonSpawn = true) ;
{
// summon gold dragon
}
}
}
}
}
}
This is throwing up this error list.
This shows my hierarchy in unity and the anchor points (the Squair crosshair looking things)
I have looked for other threads that adress this topic and they all try different methods, none work.
I am using Unity 2018.2.18f1
There are a few errors in your code here. The following is incorrect.
//get cariables from other script
DragonAncors.cs.GetComponent.<DragonTracker>() GoldDragonInit = GoldDragonSpawn;
The correct way to access this, seeing as you said DragonAncors is the parent would be:
GetComponentInParent<DragonTracker>().GoldDragonInit = GoldDragonSpawn;
This sets the GoldDragonInit Boolean to the value of GoldDragonSpawn. This has to be inside a function, as you have it outside of a function I presume you needed this set on start. Therefore I have placed it in the void Start() function. This is called at the start of the game(loaded scene).
You also do not need semi-colons ; after an if statement, however it does need to appear after every line of difinitive code. The code you have provided should instead look like this.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Dragons : MonoBehaviour {
// same as GoldDragonInit
bool GoldDragonSpawn = false;
// same number as DragonCount in DragonTrackeer
int LiveDragons;
// same as Difficulty
int DifLev;
void Start()
{
// variables from other script
GetComponentInParent<DragonTracker>().GoldDragonInit = GoldDragonSpawn;
}
System.Random RNG= new System.Random();
void update()
{
RSpawn=RNG.Next(0,2);
DragonType=RNG.Next(0,101);
if (RSpawn = 1)
{
if (LiveDragons > DifLev)
{
if (DragonType > 99)
{
// summon regular dragon
}
if (DragonType = 100)
{
if (GoldDragonSpawn = true)
{
// summon gold dragon
}
}
}
}
}
}
This works because DragonTracker is a script in the objects parent. If this was not the case then GetComponentInParent().GoldDragonInit = GoldDragonSpawn; would be replaced like so:
[SerializeField]
private GameObject DragonAncors;
void Start()
{
DragonAncors.GetComponent<DragonTracker>().GoldDragonInit = GoldDragonSpawn;
}
This is not valid c# code:
//get cariables from other script
DragonAncors.cs.GetComponent.<DragonTracker>() GoldDragonInit = GoldDragonSpawn;
Why? Because it isn't inside a method.
Also, the comment is wrong. It isn't getting a variable (typo, too), its setting a variable in another script!
The reason for the first...16 problems Visual Studio is complaining about are because of this line.
At this location you are only allowed to declare methods, fields, and properties and you're currently trying to access another class and change one of its members (something you can only do inside a method).
Additionally, you have .cs which I assume is because "DragonAnchors.cs is the file name!" which you don't need to do. I'm not sure how to go about rewriting this line (inside Start()) as I'm not sure what you're trying to actually do. That is, I don't know where an instance of DragonAnchors actually resides. You're calling GetComponent(), which is typically reserved for accessing components attached to game objects, but as you've attempted to do so on a static class reference, I'm not sure if you meant to call it on this or on something else.
This is how you can get to DragonTracker:
DragonTracker dt = GameObject.Find("DragonAncores").GetComponent<DragonTracker>()
Debug.Log(dt.DragonCount);
There are a lot of errors there and they may take some steps to go through, but first things first you should clear up the issue with the code you're trying to use being unsupported. Go into the project settings and change the compiler language version as it notes on the 5th error down. This should allow you to use the newer functionality.

simple score system in unity5

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class score : MonoBehaviour {
public int ballValue;
public Text scoretext;
// Use this for initialization
void Start () {
ballValue = 0;
}
// Update is called once per frame
void Update () {
scoretext.text = ballValue.ToString();
}
void OnTriggerEnter2D(Collider2D other)
{
if(other.gameObject.tag == "bucket")
{
ballValue = ballValue + 1;
}
}
}
ok guys what am i doing wrong over here ,i am a beginner.what i am trying to achieve here is i want my ball to fall down to the bucket and get 1 point or score ,my ball has a actual circle collider and a rigidbody and my bucket has box collider which is a trigger and both of these are prefabs which is being used multiple times in the games just in case if anyone want to know.so can anyone tell me what i am doing wrong hereor can someone guide me to the right tutorial .thank you
(after playing with it for a whilei am able to get 1 point it does not increase and i am getting this error)
Object reference not set to an instance of an object.
and it refers to this line.
void Update () {
scoretext.text = ballValue.ToString();
}
ok guys i just found the real problem,as i said the bucket is a prefab which randomly generating like the pipes in flappy bird, so after creating my core system i drag and drop the text ui into the given place ,and i apply the changes and delete that prefab and when i go back to asset and check that prefab the given place for text says none.so how can i link the text ui directly to the script so it wont dlete it self.
A way to get around this, is having a static class that holds the score and then have your buckets invoke a method in the static class to increase the score.
All you have to do then, is have an empty game object with the static class attached.

Unity3D - unable to respawn an object after it has been destroyed

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.

Categories

Resources