Clone/duplicate an existing GameObject and its children - c#

Is there a C# way in Unity to duplicate an existing GameObject and all of its children? In my case, I have an empty GameObject with a number of Text objects as children and I would like to create a copy of them all, including relative positions, text values, font, colors, etc....
Prefabs won't work easily because I want to copy the object including its current state.

The Instantiate function is used to clone any GameObject and its hierarchy.
public GameObject rootObj;
void Start()
{
GameObject duplicate = Instantiate(rootObj);
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class main : MonoBehaviour
{
public GameObject hk;
void Start()
{
hk = new GameObject("I am hk");
}
void Update()
{
hk = new GameObject("I am hk");
}
}

Related

Creating multiple spawnpoints in Unity Multiplayer

I'm kinda new to unity, been spinning my head around it this couple of last days. I've encoutered a problem where when I'm spawning 2 or more players into my scene they just get launched out of the map. I've figured out that it's a problem with the spawn points. I did set up a range between some values where they will be spawned but seems that they still spawn into the same spot and get lauched across the map.
What I want to do is, create 4 spawnpoints(the maximum number of people that can play the game) in which they will get spawned based on the number of players.
I have a function called "SetPosition" with the code:
public void SetPosition()
{
transform.position = new Vector3(Random.Range(-1,11), 0.8f, Random.Range(-4,5));
}
and it is used here, if the scene is "Game"
private void Update()
{
if(SceneManager.GetActiveScene().name == "Game")
{
if(PlayerModel.activeSelf == false)
{
SetPosition();
PlayerModel.SetActive(true);
}
Any support is appreciated, been trying to find an answer but could find anything that would fit my need.
At early stage best solution will be create 4 empty game objects at the places where you want to keep spawn point.
Then take an array of Transform to store those in script and just pass the random index to get a point.
public Transform[] points;
public Vector3 GetRandomPoint()
{
return points[Random.Range(0,point.length)].position;
}
So I've done something. I've added 4 empty objects with a parent called "SpawnManager", also made a script for the spawn manager that is down below:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnManager : MonoBehaviour
{
public static SpawnManager Instance;
Spawnpoint[] spawnpoints;
void Awake()
{
Instance = this;
spawnpoints = GetComponentsInChildren<Spawnpoint>();
}
public Transform GetSpawnPoint()
{
return spawnpoints[Random.Range(0, spawnpoints.Length)].transform;
}
}
In the PlayerModel script where I set the spawn position for the player I've added this function but it doesn't work. No errors, but it doesn't respect the spawnpoints
public void SetPosition()
{
Transform spawnpoint = SpawnManager.Instance.GetSpawnPoint();
transform.position = spawnpoint.position;
}
The SetPosition function was like this before I edited it:
public void SetPosition()
{
transform.position = new Vector3(Random.Range(-1,11), 0.8f, Random.Range(-4,5));
}

Random Obstacle Generator in unity 3D

I am looking to make my first actual game called Bottomless. It seems I am having a problem with the obstacle generator script in Unity2D. I want the obstacle to generate vertically, where a player is falling down the level.
Here my script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Generator : MonoBehaviour
{
public GameObject spike;
public float maxspeed;
public float minspeed;
public float currentspeed;
void Awake()
{
currentspeed = Random.Range(maxspeed, minspeed);
spikegen();
}
void spikegen()
{
GameObject SpikeIns = Instantiate(spike, transform.position, transform.rotation);
}
void Update()
{
}
}
Seems like running this code crashes unity quickly. Does anyone have better alternative?
So, I have been considering your problem, and I think the best thing to do would be to create spawn points in your map pieces for the spikes to fit in. Then, when your player is falling, and the new map is loaded, grab the spawn points, add them to a list, choose one randomly, and then instantiate your spike there. Or get the map pieces themselves to spawn the spikes as they are loaded.
Method 1:
Create spawn points on your map piece. Create and add the following script. Place the spawn points in the list in inspector. And call function on Awake/Start.
using System.Collections;
using UnityEngine;
public class MapScript : MonoBehaviour
{
//Spike you want to instantiate
public GameObject spike;
//List for you to place spawn points in the inspector
public List<GameObject> Spawnpoints = new List<GameObject>();
public void Awake()
{
//Get a random number from 0 to our lists count
int random = Random.Range(0, Spawnpoints.Count);
//Instantiate at the random spawn point
GameObject SpikeIns = Instantiate(spike, Spawnpoints[random].transform.position, transform.rotation);
}
}
Method 2:
Similar to the example above, except the code to spawn happens in the Generator script (this is not the preferred method as we will have to access the map piece's script).
So use the code above but remove the Awake and spike GameObject, and then for your generator script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Generator : MonoBehaviour
{
public GameObject spike;
public float maxspeed;
public float minspeed;
public float currentspeed;
void Awake()
{
currentspeed = Random.Range(maxspeed, minspeed);
spikegen();
}
void Update()
{
}
void spikegen()
{
List<GameObject> Spawners = new List<GameObject>();
foreach(GameObject spawn in refernceToOtherScripts.Spawnpoints)
{
Spawners.Add(spawn);
}
int random = Random.Range(0, Spawners.Count);
GameObject SpikeIns = Instantiate(spike, Spawners[random].transform.position, transform.rotation);
}
}
Neither of these have been tested as I am on my work computer, but they should both work perfectly fine. As you have probably guessed, there are a lot of different way to go about this.

How to access the value of cinemachine's camera distance in Unity / C#?

I'm working on Unity/C# now and I'm stuck with accessing CinemachineVirtualCamera's camera distance value in the script. What I'm trying to do is change the value of camera distance in the body section.
First of all, how can I access the CinemachineVirtualCamera component in this game object? The MoveScript is what I attached to a player game object, and I want to zoom out the camera depending on the player's movement. Since the game I'm making is small, I won't make other .cs files.
I wrote
public class MoveScript: MonoBehaviour
{
private GameObject camObj;
void Start()
{
camObj = GameObject.Find("Vertical Follow Camera");
camObj.GetComponent<CinemachineVirtualCamera>(); // <- but I get error saying, The type or namespace name 'CinemachineVirtualCamera' could not be found
}
}
I also read this document and I think the m_CameraDistance is what I'm looking for but how can I access that value?
For anyone else who wondering
GetComponent<CinemachineVirtualCamera>()
.GetCinemachineComponent<CinemachineFramingTransposer>()
.m_CameraDistance
As stated in the linked document, these classes are in Cinemachine namespace. To access the classes you have to either add
using Cinemachine;
to the beginning of your script or change your script to
public class MoveScript: MonoBehaviour
{
private GameObject camObj;
void Start()
{
camObj = GameObject.Find("Vertical Follow Camera");
camObj.GetComponent<Cinemachine.CinemachineVirtualCamera>();
}
}
And as for accessing the m_CameraDistance variable, HuySora already answered that part
Try this and don't forgot to mention namespace
public class MoveScript: MonoBehaviour
{
private CinemachineVirtualCamera virtualCamera;
private GameObject camObj;
void Start()
{
camObj = GameObject.Find("Vertical Follow Camera");
virtualCamera = camObj.GetComponent<CinemachineVirtualCamera>();
float f = virtualCamera.m_CameraDistance;
}
}

Reference to Animator component not appearing in the inspector

I have already tried to look into this... but no luck..
Sprite renderer, and mover references, work fine they appear in the inspector as I want them to.
However I am having issues in FILE 2 I am unsure of how to Serialize the Animator in the inspector.
FILE 1
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "EnemyConfig", menuName = "Enemies/Enemy config", order = 0)]
public class EnemyConfig : ScriptableObject
{
public float moverSpeed;
//public float zRotation;
public Sprite sprite;
public Animator animator;
}
FILE 2
//EnemyController.CS
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyController : MonoBehaviour
{
[HideInInspector]
public EnemyConfig config;
[SerializeField]
private SpriteRenderer spriteRenderer;
//Want to get a reference to the animator component appear in the inspector
//This is my issue...--------------------------------------]
[SerializeField]
private GetComponent<Animator> animatorController;
//----------------------------
private Mover mover;
private void Start()
{
mover = GetComponent<Mover>();
if(mover != null)
{
mover.speed = config.moverSpeed;
}
if(config.sprite != null)
{
spriteRenderer.sprite = config.sprite;
}
// related to the animator
if(config.animator != null)
{
animatorController.animator = config.animator;
}
}
}
Here you can see how the Sprite reference, and mover reference appear in the inspector.
I am trying to do the same with the Animator
GetComponent<T> is a method, it is not a type. So, you can't declare a field with this as its type. I would be surprised if this code actually even compiles. What you want is simply
[SerializeField]
private Animator animator;
Note that AnimatorController is an Editor-only class; you can't include it in your game code. Hence why you want Animator here.
Another thing to consider is, is the Animator component going to be on the same game object? If so, you don't need to serialize the reference - that would only be useful if it's going to be on a different game object, and you need to store that link at edit time.
If the Animator component is on the same object, you can do this:
private Animator animator;
void Start()
{
animator = GetComponent<Animator>();
}
The advantage is that you won't have to make sure the reference stays up-to-date, it will be connected whenever the gameplay starts. This, by the way, is the correct use of GetComponent<T> - since it's a method, you can call it within another method, not where you had it in your File2.

C# in Unity, SetActive several gameObjects from player entering trigger area

Brand new to C# and Unity.Please be nice I've been at this all night. Every tutorial I poor through says changing an object from invisible to visible is as simple as setting the game object to on. However Unity gives me an error when I declare a game object in this script. The objective is, when the trigger is entered, several game objects called 'spawn' will become visible.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class collider : MonoBehaviour
{
public gameObject Spawn; // I get error On this line that type is expected,
//not property. It wants a Transform>
private Rigidbody rb;
void Start ()
{
rb = GetComponent<Rigidbody>();
}
void OnTriggerEnter(BoxCollider other)
{
if (other.gameObject.CompareTag("Player"))
{
Spawn.SetActive(true);
}
}
}
gameObject isn't a type, but GameObject is.
Get rid of public gameObject Spawn; and use public GameObject Spawn; to declare a GameObject property called Spawn

Categories