im both new to this site and new to programming. I've been recently trying to learn new skills to help better organise/manage my code and make it both more efficient, readable and contained.
Okay well i wont go on too much about that, the problem i'm having is in XNA 3.1, I'm using C# express 08.
I have a self contained Game conponent called InputHandler, the update loops after the base loop (Game1) which so far just checks for keyboard input and stores the result into an instance of KeyboardState - which has a Get property, the only other code really is it exits Game1 if Escape key is pressed, which it checks for after storing the input.
Code:
private KeyboardState keyboardstate;
public KeyboardState Keyboard_State
{
get { return (keyboardstate); }
}
public override void Update(GameTime gameTime)
{
keyboardstate = Keyboard.GetState();
if (keyboardstate.IsKeyDown(Keys.Escape))
Game.Exit();
base.Update(gameTime);
}
moving onto the problem, another game conponent called Camera tries accessing the Keyboard_State property of the InputHandler via an instance of the IInputHandler (this is an interface btw)
public interface IInputHandler
{
KeyboardState Keyboard_State { get; }
}
it goes without saying that this interface is implemented within the InputHandler component. moving onto the error, well I have in my update loop within the Camera component some logic code, which tries to access the Keyboard_State property through the interface, check against some conditions, then alter the camera apropriatly.
private IInputHandler input;
following code is within the void update loop.. within the Camera component.
if (input.Keyboard_State !=null)
{
if (input.Keyboard_State.IsKeyDown(Keys.Left))
cameraYaw += spinRate;
if (input.Keyboard_State.IsKeyDown(Keys.Right))
cameraYaw -= spinRate;
if (cameraYaw > 360)
cameraYaw -= 360;
else if (cameraYaw < 360)
cameraYaw += 360;
}
I get a Null reference exception at the *if (input.Keyboard_State !=null)* line, complaining that it's not an instance.
I'm new with Interfaces, I've never seen much of a use for them in the past until i started to try learn XNA, and began learning about conponents, ultimately i want to create the basic components to manage a 3D game (nothing fancy, just organised and manageable).
any help would be appreciated. thanks :)
* Other info *
my camera constructer is :
public Camera(Game game)
: base(game)
{
graphics = (GraphicsDeviceManager)Game.Services.GetService(typeof(IGraphicsDeviceManager));
input = (IInputHandler)game.Services.GetService(typeof(IInputHandler));
}
and my InputHandler constructer is empty, my Game1 constructer is:
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
camera = new Camera(this);
Components.Add(camera);
input = new InputHandler(this);
Components.Add(input);
input.UpdateOrder = 0;
camera.UpdateOrder = 1;
// this component alows Asyncroniously save/load game.
Components.Add(new GamerServicesComponent(this));
#if DEBUG
fps = new FPS(this);
Components.Add(fps);
fps.UpdateOrder = 1;
camera.UpdateOrder = 2;
#endif
}
input is an instance of the Input handler game component.
private InputHandler input;
hope this helps :)
It seems to me that you are not initializing the "input"-variable in the camera anywhere ( = input is null ).
Because of that, if (input.Keyboard_State !=null) -line throws NullReferenceException ( and by the way KeyboardState is a struct thus it can't be null). You said that both InputHandler and Camera is a game-component? Try doing something like this then:
In the InputHandler constructor:
public InputHandler(...)
{
// Your initialization code here
this.Game.Services.AddService(typeof(IInputHandler), this);
}
And in the Camera constructor:
public Camera(...)
{
// Your initialization code here
input = this.Game.Services.GetService(typeof(IInputHandler)) as IInputHandler;
}
EDIT, Updated code:
Change your Game-constructor to this:
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
input = new InputHandler(this);
Components.Add(input);
Services.AddService(typeof(IInputHandler), input);
camera = new Camera(this);
Components.Add(camera);
input.UpdateOrder = 0;
camera.UpdateOrder = 1;
// this component alows Asyncroniously save/load game.
Components.Add(new GamerServicesComponent(this));
#if DEBUG
fps = new FPS(this);
Components.Add(fps);
fps.UpdateOrder = 1;
camera.UpdateOrder = 2;
#endif
}
Related
I am trying to use ParticleSystem.Emit() to dynamically emit particles, and am unable to get Emit() to work outside of the Start() method.
I am able to emit particles in the Start() method, either directly or with a separate method. When attempting to do the same in Update(), LateUpdate(), or FixedUpdate() it no longer works.
There are no errors reported. I reported the number of particles in the update methods to make sure that the code there was actually running, and it reports however many particles I emit in the Start() method.
When trying to emit particles in the update methods I have tried:
Using Emit() directly in the update loop.
Using a separate method called directly in the update loop.
Using a separate method called using Invoke() in the update loop.
I'm able to check and alter particle position in Update(), so I don't think I'm having some kind of scope problem.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test : MonoBehaviour
{
public ParticleSystem aSystem;
private ParticleSystem.Particle[] aParticle;
void Start()
{
aParticle = new ParticleSystem.Particle[aSystem.main.maxParticles];
// Emit particle.
DoEmit();
Debug.Log("Particle Count: " + aSystem.particleCount);
}
void Update()
{
int numParticles = aSystem.GetParticles(aParticle);
Debug.Log("Number of particles: " + numParticles);
for (int i = 0; i < numParticles; i++)
{
if (aParticle[i].position.z > 1)
{
aParticle[i].position = new Vector3(0f,0f,0f);
}
aParticle[i].velocity = new Vector3(0f, 0f, 1f);
}
aSystem.SetParticles(aParticle);
// Emit particle.
DoEmit();
}
void DoEmit()
{
// Configure render settings for particle.
ParticleSystemRenderer aRenderer = aSystem.GetComponent<ParticleSystemRenderer>();
aRenderer.renderMode = ParticleSystemRenderMode.Mesh;
aRenderer.mesh = Resources.Load<Mesh>("vector");
// Configure rest of settings and emit.
var emitParams = new ParticleSystem.EmitParams();
emitParams.startLifetime = 120;
emitParams.position = new Vector3(0.0f, 0.0f, 0.0f);
emitParams.velocity = new Vector3(0.0f, 0.0f, 0.0f);
emitParams.startSize = 1;
aSystem.Emit(emitParams, 1);
aSystem.Play(); // Continue normal emissions
Debug.Log("DoEmit() called!");
}
}
Expected result: A stream of particles moving in the +z direction.
Actual result: One particle moving in the +z direction.
I needed to do something similar and found this answer in the Unity forums gave me a great, reliable solution that I've reused and modified to my purposes many times. It's a particle pool from which you can emit one or more particles as needed, killing off the last particle made and reusing it once it reaches its max number of particles. I think it achieves exactly what you're looking for. I'll include the relevant script here for reference (complete with #Artifact-Jesse's colorful commentary for clarity).
Note that this script was written for Unity 2018.x, but still works great as of 2020.2.1
Artifact-Jesse's complete, functional example of a fairly generic particle pool:
using UnityEngine;
[RequireComponent(typeof(ParticleSystem))]
public class ParticlePool : MonoBehaviour
{
private int lastParticleIndex = 0; // keeps track of our oldest particle (for deletion)
// these will all be inited in Initialize() on Start()
private ParticleSystem particleSys; // our object's particle system
private ParticleSystem.Particle[] particles; // our reusable array of particles
private ParticleSystem.EmitParams emitParams; // reusable emitparams
private int maxParticles = 0; // total number of particles in our scene before re-using
private void Awake()
{
Initialize(); // initialize all of our member variables
}
public void CreateParticle(Vector3 position, float size, Vector3 velocity, float angularVelocity)
{
// if we're at our particle count limit, kill our oldest particle.
int activeParticles = particleSys.GetParticles(particles);
/// this thing sucks. Read the Unity docs VERY carefully to understand...
/// basically the parameter (particles) is an out parameter which will
/// write out the existing particles in the particle system to our
/// reusable array. After that, we can directly modify the particles
/// and then when we're done, write the particles back into the
/// particle system with ParticleSystem.SetParticles( particles, count )
if (activeParticles >= maxParticles)
{
// set lifetime to -1 to kill the particle
particles[lastParticleIndex].remainingLifetime = -1;
// we need to reset start lifetime to a normal value, too or the particle will still have infinite lifetime
particles[lastParticleIndex].startLifetime = 1;
lastParticleIndex++; // keep track of oldest particle
if (lastParticleIndex >= maxParticles) lastParticleIndex = 0;
// have to re-write
particleSys.SetParticles(particles, particles.Length); // write those pesky particles back into our ParticleSystem
}
// set up params for this particle, you can use whatever you want (see unity docs for EmitParams for what's available)
emitParams.angularVelocity = angularVelocity;
emitParams.position = position;
emitParams.startSize = size;
emitParams.velocity = velocity;
emitParams.startLifetime = float.MaxValue; // float.MaxValue makes the particle's lifetime infinite
particleSys.Emit(emitParams, 1);
particleSys.Play();
}
void Initialize()
{
if (particleSys == null)
particleSys = GetComponent<ParticleSystem>();
maxParticles = particleSys.main.maxParticles;
if (particles == null || particles.Length < particleSys.main.maxParticles)
particles = new ParticleSystem.Particle[particleSys.main.maxParticles];
}
}
Note: the particle system in this example is just bare mininum with a renderer. Not looping, no start on awake, simulation space set to World. MaxParticles is respected by the above script.
I have a spawner object. Every time a gameobject is spawned, I want that object to move randomly (wandering). The problem in my script is that the gameobject movement is very random (jittery). How can I solve this?
void Start ()
{
InvokeRepeating("SpawnNPC", Spawntime, Spawntime);
}
// Update is called once per frame
void Update () {
population = GameObject.FindGameObjectsWithTag("NPCobject");
for (int i = 0; i < population.Length; i++)
{
getNewPosition();
if (population[i].transform.position != pos)
{
population[i].transform.position = Vector3.MoveTowards(population[i].transform.position, pos, .1f);
}
}
}
void getNewPosition()
{
float x = Random.Range(-22, 22);
float z= Random.Range(-22, 22);
pos = new Vector3(x, 0, z);
}
I made the New randomize vector in different method, because I plan to change it with pathfinder function and make it in different thread/task.
You are choosing a new direction every single frame. That will always be very jittery. You wan't to only change direction after, at least, a small interval. Here is a link to one way to do that from Unity's website. https://docs.unity3d.com/ScriptReference/MonoBehaviour.InvokeRepeating.html
What about using Navigation? As you said wandering, I thought it would give you a nice result and also make your code simple.
The following screenshot is a sample with Navigation. The moving game objects are also changing their direction nicely, although it cannot be seen in the sample because the game object is capsule...
Ground game object in the sample program has NavMesh. See here to build NavMesh.
Agent game object has NavMeshAgent Component. See here to set it up.
Th Behaviour class below is for Agent game object.
using UnityEngine;
using UnityEngine.AI;
public class NavAgentBehaviour : MonoBehaviour {
public Transform[] Destinations { get; set; }
// Use this for initialization
void Start ()
{
InvokeRepeating("changeDestination", 0f, 3f);
}
void changeDestination()
{
var agent = GetComponent<NavMeshAgent>();
agent.destination = Destinations[Random.Range(0, Destinations.Length)].position;
}
}
The next Behaviour class is just for spawning the Agent and setting up the destinations. On Unity, set it to whatever game object in the scene, and allocate game objects to the fields.
using UnityEngine;
public class GameBehaviour : MonoBehaviour {
public GameObject Agent;
public Transform SpawnPoint;
public Transform Destination1;
public Transform Destination2;
public Transform Destination3;
// Use this for initialization
void Start()
{
Agent.SetActive(false);
InvokeRepeating("Spawn", 0f, 2f);
}
void Spawn() {
var newAgent = Instantiate(Agent);
newAgent.GetComponent<NavAgentBehaviour>().Destinations = new[] { Destination1, Destination2, Destination3 };
newAgent.transform.position = SpawnPoint.position;
newAgent.SetActive(true);
}
}
Increase the number of destination, to make the moves look more random. By the way, the destinations do not need to be specified by game objects, which is only for making it easy to see the sample program's behaviour.
The source of the jitteriness comes from the fact that you are updating the position to move every frame so your objects never have a consistent location to move to. I would instead suggest attaching a new script to each of your objects that individually handles their movement. In that script you could do something like the following, which has a delay to keep the target position for more than 1 frame.
float delaytimer;
Vector3 pos;
void Start () {
getNewPosition(); // get initial targetpos
}
void Update () {
delaytimer += Time.deltaTime;
if (delaytimer > 1) // time to wait
{
getNewPosition(); //get new position every 1 second
delaytimer = 0f; // reset timer
}
transform.position = Vector3.MoveTowards(transform.position, pos, .1f);
}
void getNewPosition()
{
float x = Random.Range(-22, 22);
float z= Random.Range(-22, 22);
pos = new Vector3(x, 0, z);
}
You are changing the direction they are moving in every frame, thats what is causing the jitter.
You could wait a few moments before you change the direction, perhaps something like this.
// Outside update
float betweenChanges = 2;
float lastChange = 0;
// Inside update
if(Time.realtimeSinceStartup > lastChange)
{
// Change directions
// ...
lastChange = Time.realTimeSinceStart + betweenChanges;
}
You could also solve this by using InvokeRepeating or a Coroutine.
If you dont want all the NPC's to change direction at the same time and still plan on controlling every NPC from the same class like in your example, you should perhaps add a timer for each NPC instance instead and use that to decide when to change its direction.
A better idea would be to let each NPC have its own Movement-script.
I'm somewhat new to PUN and Unity so hopefully, I am making some kind of beginner mistake.
void Update(){
if(launch == true){
Debug.Log("launched");
myPhotonView.RPC("ChangeScene", PhotonTargets.All);
}
//myPhotonView.RPC("ChangeScene", PhotonTargets.All);
}
When I run the code above, I can see launched in the console but I get
"NullReferenceException: Object reference not set to an instance of an
object" on this line: myPhotonView.RPC("ChangeScene",
PhotonTargets.All);
When I run it with that line commented out and the line that's outside the if statement uncommented, there is no null reference exception and the method executes. Is there a mistake in the above code, or is this a bug in Photon?
Any help at all is much appreciated. I can post the full code or error messages if anyone thinks it's necessary.
Also, this is less important, but myPhotonView is null in any methods I create that aren't regular MonoBehaviour methods like Start or Update even though I set it as a global variable and filled it in Start before I try to access it. This seems like it might be tied to the other problems I'm having, and it's the only reason I'm using Update for this.
Edit: Here's the entire file:
using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
public class NetworkedPlayer : Photon.MonoBehaviour{
public GameObject avatar;
public PhotonView myPhotonView;
public bool launch = false;
public string destination = "";
//Responsible for avatar movements on the plane
public Transform playerGlobal;
//Responsible for headmovements
public Transform playerLocal;
public Transform playerRotation;
void Start (){
//launch is successfuly set to false
//if(!launch) Debug.LogError("banana");
Debug.Log("Instantiated");
//Necessary for photon voive to work
var temp1 = PhotonVoiceNetwork.Client;
myPhotonView = this.photonView;
//this ensures that only you can control your player
if (photonView.isMine){
Debug.Log("Controlling my avatar");
playerGlobal = GameObject.Find("OVRPlayerController").transform;
playerLocal = playerGlobal.Find("OVRCameraRig/TrackingSpace/CenterEyeAnchor/Pivot");
playerRotation = playerGlobal.Find("OVRCameraRig/TrackingSpace/CenterEyeAnchor");
this.transform.SetParent(playerLocal);
this.transform.localPosition = Vector3.zero;
this.transform.rotation = playerRotation.transform.rotation;
// avatar.SetActive(false);
//Throws null
//GetComponent<PhotonVoiceRecorder> ().enabled = true;
}
}
void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info){
//This sends your data to the other players in the same room
if (stream.isWriting){
stream.SendNext(playerGlobal.position);
stream.SendNext(playerGlobal.rotation);
stream.SendNext(playerLocal.localPosition);
stream.SendNext(playerLocal.localRotation);
}
//This recieves information from other players in the same room
else{
this.transform.position = (Vector3)stream.ReceiveNext();
this.transform.rotation = (Quaternion)stream.ReceiveNext();
avatar.transform.localPosition = (Vector3)stream.ReceiveNext();
avatar.transform.localRotation = (Quaternion)stream.ReceiveNext();
}
}
public void ChangeAndSyncScene(string dest){
Debug.LogError("Dest selected: " + dest);
launch = true;
destination = dest;
Update();
}
void Update(){
if(launch == true){
Debug.LogError("launched");
myPhotonView.RPC("ChangeScene", PhotonTargets.All);
ChangeScene();
}
myPhotonView.RPC("ChangeScene", PhotonTargets.All);
}
[PunRPC]
void ChangeScene(){
Debug.LogError("scene changed");
Application.LoadLevel (destination);
}
}
Edit: I never managed to fix this, but I did get around it. I created gameobjects to give values to other players in the game. PM me for more info
Hopefully this isn't too much detail, I'm not used to asking programming questions.
I'm attempting to do the 3D Video Game Development with Unity 3D course that's on Udemy, though using C# instead of Javascript. I just finished up the tutorial that involves creating a space shooter game.
In it, a shield is created by the user when pressing a button. The shield has a "number of uses" variable that does not actually get used by the time the tutorial has finished. I'm trying to add it in, and have successfully managed to implement it so that with each use, we decrease the number of uses remaining, and no longer are able to instantiate the shield once that number is <=0.
This variable is stored on the player, and if I print it from the player, it returns the value I would expect.
However, I'm using a separate SceneManager.cs (this is where the tutorial placed the lives, and score, and timer variables ) where I print numbers into the GUI. My problem is that I cannot get my number of uses variable to stay current when I try to print it from the scene manager... it registers the initial value, but doesn't update after that.
Here is the Player Script
using UnityEngine;
using System.Collections;
public class player_script : MonoBehaviour {
// Inspector Variables
public int numberOfShields = 2; // The number of times the user can create a shield
public Transform shieldMesh; // path to the shield
public KeyCode shieldKeyInput; // the key to activate the shield
public static bool shieldOff = true; // initialize the shield to an "off" state
public int NumberOfShields
{
get{return numberOfShields;}
set{numberOfShields = value;}
}
// Update is called once per frame
void Update()
{
// create a shield when shieldKey has been pressed by player
if (Input.GetKeyDown (shieldKeyInput)) {
if(shieldOff && numberOfShields>0)
{
// creates an instance of the shield
Transform clone;
clone = Instantiate (shieldMesh, transform.position, transform.rotation) as Transform;
// transforms the instance of the shield
clone.transform.parent = gameObject.transform;
// set the shield to an on position
shieldOff = false;
// reduce the numberOfShields left
numberOfShields -=1;
}
}
print ("NumberOfShields = " + NumberOfShields);
}
public void turnShieldOff()
{
shieldOff = true;
}
}
when I run "print ("NumberOfShields = " + NumberOfShields);" I get the value I expect. (astroids trigger the turnShieldOff() when they collide with a shield.
Over in my Scene Manager however... this is the code I'm running:
using UnityEngine;
using System.Collections;
public class SceneManager_script : MonoBehaviour {
// Inspector Variables
public GameObject playerCharacter;
private player_script player_Script;
private int shields = 0;
// Use this for initialization
void Start ()
{
player_Script = playerCharacter.GetComponent<player_script>();
}
// Update is called once per frame
void Update ()
{
shields = player_Script.NumberOfShields;
print(shields);
}
// GUI
void OnGUI()
{
GUI.Label (new Rect (10, 40, 100, 20), "Shields: " + shields);
}
}
Any idea what I'm doing wrong that prevents shields in my SceneManager script from updating when NumberOfShields in my player_script updates?
I think you might have assigned a prefab into playerCharacter GameObject variable instead of an actual in game unit. In this case it will always print the default shield value of prefab. Instead of assigning that variable via inspector try to find player GameObject in Start function. You can for example give your player object a tag and then:
void Start() {
playerCharacter = GameObject.FindGameObjectWithTag("Player");
}
Within my 2d game i wsih to have a number of OnGui elements there for the user to select, however, the cursor that im using is another ongui element(using kinect to navigate) is this possible by any chance, at the moment im using planes but i will be zooming in and out of the camera so ill essentially need them attatched to the screen. Any ideas, suggestions or workarounds.
THis is currently my cursor.
using UnityEngine;
using System;
using System.Collections;
public class PillarAgent : MonoBehaviour {
public SkeletonWrapper sw;
public Vector3 distance;
public float progress =0f;
public Texture2D cursor;
public Texture2D load;
public Camera mainCam;
public float startTime;
private int roundedRestSecounds;
// Use this for initialization
float differencex = 0;
float differencey = 0;
void Start () {
distance =new Vector3(0f,0f,0f);
}
float translate(float value, float leftMin, float leftMax,
float rightMin,float rightMax)
{
float leftSpan = leftMax - leftMin;
float rightSpan= rightMax - rightMin;
float valueScaled = (value-leftMin)/(leftSpan);
return rightMin+(valueScaled * rightSpan);
}
// Update is called once per frame
void Update () {
if (sw.pollSkeleton())
{
distance.x=sw.bonePos[0,0].x - sw.bonePos[0,7].x;//5 is left shoulder
distance.y=sw.bonePos[0,0].y -sw.bonePos[0,7].y;
differencex=translate(distance.x,.6f,0,0,Screen.width);
differencey=translate(distance.y,-.5f,0,0,Screen.height);
//Debug.Log();
float width = sw.bonePos[0,5].x+ sw.bonePos[0,9].x;
float height =sw.bonePos[0,4].y- sw.bonePos[0,0].y;
float heightdiv= (height/2)+sw.bonePos[0,0].y;
}
}
void OnGUI() {
//left top width height
Rect r = new Rect(differencex,differencey,80,50);
GUI.Label(r,cursor);
GUI.BeginGroup(new Rect(differencex,differencey+50,50*Mathf.Clamp01(progress),15));
//Debug.Log(progress);
GUI.DrawTexture(new Rect(0,0,50,50),load);
GUI.EndGroup();
transform.position =mainCam.ScreenToWorldPoint(new Vector3(differencex,Screen.height-differencey,50));
//mainCam.fieldOfView()
}
void OnCollisionStay(Collision Other)
{
startTime+=Time.deltaTime;
if(Other.gameObject.GetComponent(typeof(TextControl)))
{
roundedRestSecounds=Mathf.CeilToInt(Time.time);
progress = Time.time *0.2f;
CurrentState=true;
}
else if(Other.gameObject.tag==("Scalpal")){
progress = startTime *0.5f;
//scallpall activated
//
}
}
void OnCollisionExit(Collision Other){
startTime =0f;
progress =0f;
}
public Boolean CurrentState{get;set;}
}
The next class is essentially the class in which i pick up my tools, currently this code doesnt work(not sure why), but what i wish to do is select some tools which show up on the screen so that i can use them,for e.g pick up paint brush start painting bricks or what not. at the moment i have my tools on a plane, i wish to always have them on the screen at all times when the camera moves.
using UnityEngine;
using System.Collections;
public class SelectTool : MonoBehaviour {
public Tools tools;
public float startTime;
public bool ScalpalSelected;
public GameObject selectedTool;
void Start()
{
tools = this.GetComponent<Tools>(); //in order to use this tools muyst be attached to the game object
//this is essentially saying with regards to this game object get the component named tools
}
void update()
{
}
void OnCollisionStay(Collision Other)
{
startTime +=Time.deltaTime;
if(startTime >5f){
if(Other.collider.tag==("Scalpal"))
{
selectedTool = Other.collider.gameObject;
Debug.Log(selectedTool+" What in gods good name is:" +tools.utilities[0]);
}
else {
selectedTool=null;
}
if(selectedTool){
for(int i=0;i<tools.utilities.Length;i++)
{
}
}
ScalpalSelected=true;
renderer.material.color = Color.yellow;
}
}
void OncollisionStay(Collision other){
startTime = 0f;
}
}
From the comment section to the question I will assume that you want to know how to do this:
"... you want your plane objects to move together with the camera ..." - Steven Mills
"thank you #StevenMills Do you have any example of how this can be done?" j bel
While the answer provided in the comments is to just manually add the planes as children of the camera (a very straightforward, manual approach), I will give another way to do this through scripting (in light of maybe this will help someone else out disregarding the likeliness of someone using this solution).
The idea of this is to create a script (thus following being attached to the MainCamera) that will search through all of the GameObject in the Object Hierarchy with the method GameObject.FindGameObjectsWithTag. Once we have all our GameObject with the associated Tag, we can then loop through the array and parent the attached script's GameObject to each.
public class ParentGameObjects : MonoBehaviour {
//The tag to search for on all game objects in the hierarchy
public String objectTag;
//The game objects that we will parent the main camera to
private GameObject[] children;
//It's not necessary to store references to the children but if you want to modify them at some point you will be able to
void Start() {
//Find all game objects with the tag we want
children = GameObject.FindGameObjectsWithTag(objectTag);
//Loop through all of the game objects found and parent this object's transform
for(int i = 0; i < children.Length; i++) {
children[i].transform.parent = transform;
}
}
}
Now, there are a few things you have to do for this script to work:
Attach this script to any GameObject that you want to parent other objects to.
In the Inspector of the GameObject that the script is attached to, enter in the name of the Tag you want to use.
For all GameObject(s) in the Hierarchy that should be added as children, assign the same Tag.
Of course there are other things you can do like, for example, instead of only searching for one Tag be able to search for multiple but that requires a bit (not exactly much) more work. Nonetheless, I hope this will at least be useful information to someone on how parenting works via scripting.