How to edit a prefab to move a child object position - c#

I am programming an endless runner that manipulates an airplane with the flexion of the wrist. I have a set of prefabs that move in front of the player. I have a simple prefab, it's a platform and an object called "Bone" as a child. his "Bone" each time the player touches it gives him 1 pt. However, I want to know (if possible) how to change the position of this child object via script. I have written a rough code of the main idea:
//This is my main prefab
var assetPath = "Assets/BonusH.prefab";
//Find the child "Bone"
var bone = GameObject.Find("BonusH/Bone");
//Edit mode
using (var editingScope = new
PrefabUtility.EditPrefabContentsScope(assetPath))
{
//Set the new location inside the prefab
bone.transform.Translate(1,1,1);
}

Related

Unity: Change UI gameObject parent and position without moving Child gameObject

I have a UI in Unity where I constantly move items from one place to another.
Some of said items are containers, and I decided to give each containers their own child gameObject representing and containing the actual container's content once opened (aka activated the gameObject). I chose to do it this way to be easier to track each container's actual containers.
What I want: When changing the item's parent (aka moving it around since all my parents have layout groups), the child gameObject should remain at the same world position
What I have: When changing the item's parent, the child gameObject changes world position
What I can do: I could reset the position of the child gameObject each time, as I do the first time the gameObject is instantiated using this code (the relative gameObject is stretched)
Vector3[] corners = new Vector3[4];
transform.parent.parent.GetComponent<RectTransform>().GetWorldCorners(corners);
float width = corners[2].x - corners[0].x;
float height = corners[1].y - corners[0].y;
RectTransform itemTransform = item.transform.GetChild(1).GetComponent<RectTransform>();
itemTransform.position = new Vector3(width / 2, height / 2);
What I want to know: Is there something built in Monobehavior or Unity that prevents a child gameObject from moving
Here are images step by step of one of the cases it would apply:
Here I have a bag item called "sac a dos" in my room
Now I have opened The bag, which shows up in the middle of the screen
I now have created a chest item called "Coffre" at the same place, causing the bag to be put as child of the chest's container child gameObject
Here I opened the chest, positioned at the right place, and showing the bag that was put as child of the chest's container child gameObject
Here I opened the bag in the chest, causing the bag's child gameObject to be misplaced since the bag's position changed
I think You should separate items data from their display.
When You have a common display of your elements write a Show method, where you could pass showed item data.
Example:
public class ItemDisplay : MonoBehaviour
{
public void Show(ItemData itemData)
{
this.gameObject.SetActive(true);
foreach (var property in itemData.properties)
{
DisplayProperty(property);
}
}
private void DisplayProperty(){...}
}

Instantiating a U.I object at the position of another object while keeping the Canvas as the parent

Ran into a U.I problem that I am struggling to solve (UI is always an issue for me). Gist of the project is that I have an array of spawn points (Positions[i]), an array composed of enemy prefabs(Enemies[j]) and just a UI panel prefab with a text component (EnemyHUD). When I pass string names through a certain function, as long as there is a prefab with the same name and position available to it, it will load in the enemy. Now, for every enemy prefab loaded in, I would like a "EnemyHUD" prefab to instantiate at at the enemy positions and with text displaying the name of the enemy.
GameObject HUD = Instantiate(EnemyHUB, Positions[i].position, Positions[i].rotation);
This line spawns the EnemyHUD prefab at the right location but its Instantiates them outside of the canvas so they show up as red x's. So I added this:
HUD.transform.SetParent(GameObject.Find("Canvas").transform, false);
This fixes the issue of Instantiating outside of the canvas but also (irritatingly)resets the Instantiate position and embarrassingly, I'm not sure how to set it back while making sure it stays a child of the Canvas. Have not event touched the name change part yet.
I have been working on this this since last night and while I got a lot of different results experimenting, none have been the one that I want. Very much still a novice, so I am sure it is looking me in the face so please help me find it.
First of all I would strongly recommend to avoid Find whenever possible! Rather already reference the according Canvas and store its reference. Especially the i lets assume you are doing this in a loop so using Find repeatedly is extremely inefficient!
// Drag you Canvas object into this field via the Inspector in Unity
[SerializeField] private Canvas _parentCanvas;
private void Awake()
{
// use this only as fallback an only ONCE
if(!_parentCanvas) _parentCanvas = GameObject.Find("Canvas");
if(!_parentCanvas) Debug.LogError("Could not get Canvas!", this);
}
Well and then the second parameter of Transform.SetParent is called
worldPositionStaysIf true, the parent-relative position, scale and rotation are modified such that the object keeps the same world space position, rotation and scale as before.
And
The default value of worldPositionStays argument is true.
Simply either leave it out like
HUD.transform.SetParent(_parentCanvas);
// this equals
//HUD.transform.SetParent(_parentCanvas, true);
or you could even do it in one single go already in Object.Instantiate which takes an additional parameter
parent Parent that will be assigned to the new object.
// This directly instantiates the new hud as child of _parentCanvas
// while still taking the position and rotation in absolute worldspace
GameObject HUD = Instantiate(EnemyHUB, Positions[i].position, Positions[i].rotation, _parentCanvas);

How to create scriptable object from scene in unity editor

I am currently creating a 2D-game in Unity and facing troubles in level design. I would like to create about 100 levels, each with different prefabs at different positions.
In order to load up the proper levels I have built an architecture with scriptable objects. Tilemaps are being used to represent obstacles. So it is possible to have about 30 different tile-positions for each level. It seems wrong to me to fill in those informations on every scriptable object seperatly.
What I am now looking for is a way to create a level in the editor and save the data directly in a scriptable object. To have a button in editor which says: "Save current scene-layout in e.g. scriptable object level 3". And also being able to load every level to the scene in editor mode.
You create your level in a prefab and reference this prefab into your ScriptableObject.
So your level prefab contains your tilemap and other prefabs.
I would suggest Raphael solutions, but in some cases this can be hard if you are deal with prefabs issues.
Other way to achive this would be create your custom editor to iterate your scene and create this ScriptableObject.
I use this code for something similar
GameObject __PARENT = GameObject.Find("__PARENT");
Vector3 centroid = Vector3.zero;
Transform[] childs = __PARENT.transform.GetComponentsInChildren<Transform>();
foreach (Transform go in childs)
{
Debug.Log(go.name);
centroid += go.position;
}
centroid /= (__PARENT.transform.childCount);
GameObject centerPivotObject = new GameObject();
centerPivotObject.name = "CenterPivotObject";
centerPivotObject.transform.position = centroid;
foreach (Transform go in childs)
{
go.parent = centerPivotObject.transform;
}
In my case I was trying to center pivot in parent object, but you can combine this iterate over your parent game using this and create using this your ScriptableObject
https://wiki.unity3d.com/index.php/CreateScriptableObjectAsset

Moving every child

I have a game object that has a lot of children (spheres)
At some stage of the game I'd like to move every child down smoothly so it would look like it's falling apart. What I've tried is using foreach loop to move every element with Vector3.Lerp. Sadly everything starts lagging very badly.
Would be great to have them fall down smoothly like this
foreach (Transform child in GameObject.Find("Carbon").transform)
{
child.transform.position = Vector3.Lerp(child.transform.position,
new Vector3(child.transform.position.x,
child.transform.position.y - 200,
child.transform.position.z), 0.2f);
}
I think the main problem comes from GameObject.Find(). From the look of your code, it finds carbon transform in every foreach. If you have 100 objects it will use "GameObject.Find" 100 times in one frame.
This can be fixed by caching transform:
List<Transform> carbonList = new List<Transform>();
void Start () {
//cache carbon tranform in Start() or OnEnable()
carbonList.AddRange( transform.GetComponentsInChildren<Transform>());//use this if you attach your code in object parent
//loop transform form caching list so it will not keep finding transform and cause lagging
foreach (Transform child in carbonList)
{
var childPos = child.position;
child.position = Vector3.Lerp(childPos, new Vector3(childPos.x, childPos.y - 200, childPos.z), 0.2f);
}
}
if your script is not in parent object you can use find tag instead.
http://answers.unity3d.com/questions/24257/how-do-i-find-all-game-objects-with-the-same-name.html
Your animation graphic seems to show that all of your spheres maintain the same relative position to each other. Rather than "falling apart", they seem to be falling together as a body. If that's want you want, rather than animate each individual sphere, put them all under a single parent object and animate that parent.

How to use UI.Text as a prefab in Unity?

I've tried using this
Instantiate(entry, new Vector3(x, y, 0), Quaternion.identity);
It successfully created objects, as seen in my hierarchy. But I cannot see the text on the screen, even though there is a text assigned to it. I can only see an empty game object on the screen.
These screenshots show the game on play, and the selected object is the object instantiated through the script.
When I drag the prefab, it does not show anything on the scene. This happens to all my prefabs. The following are its components:
In new Unity3D UI system, every UI (Text, Button, Panel etc.) component that will be renderer on screen must have a parent Canvas component.
You actually do use such approach in your project, where you have Toolbar, List etc. that have parent called Canvas and which I suppose has Canvas component attached.
What you need to do is to move instantiated gameObject to be child of other gameObject that holds Canvas component.
As there can be multiple components of Canvas type, I would suggest to add possibility to assign root for instantiated objects inside your Script.
Script:
//Drag and drop this from inspector; make sure that dragged gameObject
//has Canvas component in it or above it (in parent)
public Transform EntriesRoot;
void Start()
{
var entry = Instantiate(entry, new Vector3(x, y, 0), Quaternion.identity);
//Put parent to our EntriesRoot
//EntriesRoot will be our new parent for entry in hierarchy
entry.transform.SetParent(EntriesRoot)
}
they need to be a child of a Canvas, that displays them.
// find canvas
GameObject canvas = GameObject.Find("Canvas");
// clone your prefab
GameObject text = Instantiate(entry, new Vector3(x, y, 0), Quaternion.identity);
// set canvas as parent to the text
text.transform.SetParent(canvas.transform);
For each instance, you might have to manually enable the guiTexture.

Categories

Resources