I am trying to attain the legendary skill of mastering how to make my scripts talk with any GameObject and their components wherever they are. To do that, i watched a couple of tutorials like https://www.youtube.com/watch?v=LrkfSqxz4jU, but my brain still seem to resist to smartness :(.
So far, i have understood than in order to do that i first need my
script to find the right gameobject in my scene (if the script is not
attached directly to it), and assign it to a variable, with for
example:
myVariable = GameObject.Find ("MyGameObjectName");
Then, when i have found this gameobject (and eventually summoned it if it was not in my scene), i find myself at loss to figure out how to call the right component (and inherently, how to call the right sub-element.
For example, i have at the moment a game object for my UI with :
RectTransform, CanvasRenderer,UI Controller (Script),Grid Layout Group (Script)
In order to modify the RectTransform 's Pivot X for example, my logic tells me to add to my script:
myVariable.GetComponent<RectTransform> ();
myVariable.RectTransform.Pivot.x = 0.75;
...Which get all red and bad, and i don't understand why. I am also not knowing how i am supposed to call the component GridLayoutGroup. I suppose there is a even dirtier trick in the sense that it is written (script)...
To give you another example that i find confusing, if i would type myVariable.transform.position.x , is it changing the RectTransform, or another hidden transform that i don't know of ?
It is confusing because i would think that logically, this should be called instead myVariable.RectTransform.position.x or something.
So the point of all that is: What's the big idea ? What is the core concept that i am missing ?
I am confused ! :D
Because having public fields is bad practice (accessible from everywhere) you should use serialized fields.
I'll just use the example Vancete made up, but with a serialized field instead of a public field.
[SerializeField] GameObject myGo; // a space to drop a GameObject will appear in the inspector too,
// with the benefit of not having a public field
// (not specifying public, private, protected etc. makes the field private in C#)
void Start() {
Image myImg = myGo.GetComponent<Image>();
myImg.sprite = // WHATEVER
myImg.color = // YOUR PREFERRED COLOR
}
At the bottom of this page, you'll find a nice table, comparing these modifiers.
These people here are all proving my concept. As the user, who wrote the last answer on the linked page, points out, even Unity is using [SerializeField] in their example project.
You'll find another proof in this article.
The fastest and best way to access a GameObject is declaring it as public and drag&dropping in the inspector.
GameObject.Find is slow (since it requires a tree search) and impractical (you will have problems if you rename the GameObject or change its hierarchy), things that can be avoided linking it in the mentioned way above.
For example, using GameObject.Find inside the Update is a real performance killer.
Also, if you are going to access to a GameObject component more than once, it's recommended to reference it before using it.
public GameObject myGo; // a space to drop a GameObject will appear in the inspector
void Start(){
Image myImg = myGo.GetComponent<Image>();
myImg.sprite = // WHATEVER
myImg.color = // YOUR PREFERRED COLOR
}
Related
The Unity Manual says the Resources.Load returns the requested asset as an Object.I wonder why could't I use the returned Objectdirectly.For example,I have a Text prefab and I want to add it's instance to the Hierarchy,but the Code below won't work
Text prefab;
private void Start()
{
prefab = Resources.Load<Text>("Prefabs/Text");
GameObject canvas = GameObject.Find("Canvas");
prefab.transform.SetParent(canvas.transform);
}
I must Instantiate the return of the Resources.Load first like below
Text prefab;
private void Start()
{
prefab = Resources.Load<Text>("Prefabs/Text");
GameObject canvas = GameObject.Find("Canvas");
Text text = Instantiate(prefab);
text.transform.SetParent(canvas.transform);
}
I don't know what's the difference between the Instantiate result and Resources.Load result,and what the Instantiate do ,so that it's return can be added to Hierarchy.
Forgive my poor English!
To use the Method Instantiate(GameObject) you would write a new component, create a new variable of type GameObject, attach the component to an GameObject, and fill the variable in the inspector.
To use the Method Instantiate(Resource.Load("object path")) you just need the name/path of the Prefab.
this is extremely useful if you have a huge amount of generated parts in your game (so there are no gameobjects placed in the editor), if you'd want to avoid Resource.Load you'd need some "data-holder-gameobject" placed in an nearly empty scene. edited to make my point a bit clearer
it is aswell helpfull if you have large number of different Prefabs and your method knows the name of the object it wants to build, or you just simply dont want to drag and drop all those prefabs into the inspector window
Resource.Load, loads data from your drive. it's possible that your game is played from a Hard drive, which would mean to load the prefabs the hard drive needs to rotate, position the read-head, and so on.
Instantiate is slow itself even without the need of Resource.Load Instantiate is not that fast. if it happens that you need it very often ( multiple times per second) you should consider some kind of object-pool 1
I have a lot of Game Objects I need to Instantiate and put on scene on possible positions.
I have a list of rules where GameObject can be put by player (e.g. small box only at big box, sphere only on small box etc.)
I know I can put every rule into an "if", but I think it's not the most efficienty way. How should I keep a list of rules where can user put GameObjects? How my scripts should check and show possible positions? I will be thankful for any ideas how to start, to make it elegant and efficient.
There are many ways to do this.
What i would prefer is to keep everything organized and configurable per object (looking at the object oriƫnted programming structure).
I suggest defining per object where it can be placed. Here an example.
public yourClass
{
public GameObject ObjectToPlace;
public List<GameObject> ObjectToPlaceOnList;
public bool CanObjectBePlaced(GameObject targetObjectToPlaceUpon)
{
if (ObjectToPlaceOnList.Contains(targetObjectToPlaceUpon))
{
return true;
}
return false;
}
}
Your script may look different ofcourse, based on your current scripts.
I need a way to add a script to an object that I just Instantiated. Ideally I could just set the script to add in the inspector. The problem is that I can't use
public Component scriptToAdd;
because then I would need to already have an empty object or something with the script on it. While that would work it feels kind of dirty or hackish to make an empty that just stores references to something. Also the point of doing it like this for me is to make it more efficient to swap out different scripts. If I had to swap out a script on an empty and then drag the new one in I'd lose on some of that efficiency I'm after. Thanks for any help.
After you instantiate, you should use the GameObject.AddComponent() Class, to add any component Type you want.
for example, if you want to add a camera to the scene.
void Start () {
GameObject myNewCamera = new GameObject();
//creates an empty game object, you can already attach components to it.
myNewCamera.AddComponent<Camera>();
//adds a component of type Camera
}
You can also use the overloaded constructor
GameObject myNewCamera = new GameObject("my object name", typeof(ScriptToAdd));
GameObject myNewCamera = new GameObject("my object name", typeof(ScriptToAdd), typeof(MoreComponentsToAdd));
Also, you should never be afraid of using an empty GameObject on your scene, for keeping information, references, variable values, saves, or anything really. It doesn't really affect the performance of your game, and you can make your life easy just by having an easy to find tag, such as "Engine".
Then you can access anything just by adding:
GameObject.FindGameObjectWithTag("Engine");
I hope I was able to help you :)
-Noe
I have been trying to use SetActive () to turn on and off GameObjects.
I couldn't figure it out and ended up using:
GameObject.Find ("ObjectName").GetComponent<Image> ().enabled = false;
to turn off an image.
I am not trying to use the same script to turn off a GameObject that has multiple animations nested inside it.
GameObject.Find ("ObjectName").GetComponent<???> ().enabled = false;
GameObject.Find ("ObjectName").SetActive (false);
I am not sure what goes in the <>, but I have read I can do it with SetActive (), but that doesn't seem to work and gives me an "Object Reference not set to object" error.
So what is the difference between these two and how would I use them properly?
Using GetComponent allows you to enable/disable and interact with specific components on a GameObject.
For example, you may need to disable a GameObject's rigidbody at some point, but you still want that object, and everything else on it to be active. So you could simply say:
GameObject.Find("MyObject").GetComponent<Rigidbody>().enabled = false;
Note that what goes inside the "<>" is the class name of the component you want to interact with.
For example, if you had a script you have written yourself on a gameobject called MyScript, you could grab hold of it like so:
MyScript script = GamesObject.Find("MyObject").GetComponent<MyScript>().enabled = true;
Additionally, another good use of GetComponent is reading information from a script on an object.
For example, if you had a script called Health with a public variable HitPoints on an object, another script could gain access to that information using GetComponent.
if( enemyGameObject.GetComponent<Health>().HitPoints < 0 )
{
enemyGameObject.SetActive(false);
}
Using SetActive will enable and disable a GameObject entirely. This is less expensive than deleting / making a new object, and is thus often used in techniques like Object Pooling.
For example, if you had a GameObject that you needed disabled, but you knew you were going to need it again soon, it is far less expensive to just call
MyGameObject.SetActive(false);
...
MyGameObject.SetActive(true);
Than it is to delete that object entirely, and then make a new one when you are ready for it again.
To add up to the other answers, when a component is disabled it means the MonoBehaviour callbacks are not called anymore. So no Update, FixedUpdate, OnCollisionXXX and so on.
Awake is called when the object is created so it is obviously enabled by default at that stage. Start is called on the first run after Awake. So if you set the component off in Awake, Start will wait until you set it back on from elsewhere.
OnEnable/OnDisable are called when you modify the enabled property.
SetActive works on the GO and is pretty much a shortcut to disable all components at once.
gameObject.SetActive(false);
foreach(var comp in GetComponentsInChildren<MonoBehaviour>()){
comp.enabled = false;
}
those are fairly similar in result (maybe not in efficiency). Actually, when you set a game object on/off, the OnEnable/OnDisable of each component is called. All MonoBehaviour callbacks are not called anymore if you set the object off.
So, the choice is dependent on what you are after, if you wish to disable movement but still see the object and other actions:
GetComponent<Movement>().enabled = false;
if you wish to kill an enemy:
enemy.gameObject.SetActive(false);
Note that even though a component is disable, does not mean you cannot interact with it. You can still manually call any method on it. Consider this:
AnyComponent ac = gameObject.GetComponent<AnyComponent>();
ac.enabled = false;
ac.AnyMethod();
Valid and will do what it is meant to do considering it does not require an Update or a FixedUpdate (Physics action).
A deactivated component cannot be found with GetComponent, you can get it with GetComponentInChildren(true) since it also searches the game object and its children. I am not sure whether it returns the first found or the first active found.
myGameObject.SetActive(false);
AnyComponent ac = myGameObject.GetComponent();
AnyComponent acic = myGameObject.GetComponentInChildren(true);
even though the GO has a AnyComponent attached, ac is null, acic is not (seems to be a 5.3 feature though).
http://docs.unity3d.com/ScriptReference/Component.GetComponentInChildren.html
Finally, for a component to expose the tick, it needs to have a Start method in the script (don't ask why...).
Setting .enabled turns one component on a GameObject on or off, e.g. an Image. Using SetActive() turns the whole GameObject on or off.
Choosing which to use should correspond with what you want to disable.
There are some hand wavey answers for this on answers.unrealengine.com, but they seem to lack any detail or examples.
Specifically, and in detail, if you wanted to implement a set of dynamic textured quads which rendered in the 3d game world, how would you do it?
For use case, consider a 2dish side scroller that uses Spriter animations. The 2D animations are loaded from XML easily enough, but how do you then render this 2D set of textured, rotated and scaled quads dynamically on the scene?
Is the problem you are facing concern spawning the mesh or with obtaining the right orientation? (i.e. orthographic projection, facing the camera)
Spawning the mesh is easy enough, can be done either through Blueprints or in code.
In Blueprints, you would set up certain preconditions and then choose to spawn actors based on the conditions.
The actual coding solution would look much the same.
If it is regarding orientation, then this answer will be of help to you, found on the UnrealEngine forums:
https://answers.unrealengine.com/questions/62126/how-do-i-render-a-dynamic-mesh-with-orthographic-p.html
EDIT:
After much hair pulling and documentation surfing, here's the code that made things work.
ADynamicMeshSpawner::ADynamicMeshSpawner()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
// Using a SphereComponent is not particularly necessary or relevant, but the cube refused to spawn without a root component to attach to, or so I surmise. Yay Unreal. =/
USphereComponent* CubeComponent = CreateDefaultSubobject<USphereComponent>(TEXT("RootComponent"));
RootComponent = CubeComponent;
CubeComponent->InitSphereRadius(40.0f);
CubeComponent->SetCollisionProfileName(TEXT("Pawn"));
// Create and position a mesh component so we can see where our cube is
UStaticMeshComponent* CubeVisual = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("VisualRepresentation"));
CubeVisual->AttachTo(RootComponent);
static ConstructorHelpers::FObjectFinder<UStaticMesh> SphereVisualAsset(TEXT("StaticMesh'/Game/StarterContent/Shapes/Shape_Cube.Shape_Cube'"));
if (SphereVisualAsset.Succeeded())
{
CubeVisual->SetStaticMesh(SphereVisualAsset.Object);
CubeVisual->SetRelativeLocation(FVector(-200.0f, 0.0f, 100.0f));
CubeVisual->SetWorldScale3D(FVector(2.0f));
}
// Create a material to be applied on the StaticMeshComponent
static ConstructorHelpers::FObjectFinder<UMaterial> Material(TEXT("Material'/Game/StarterContent/Materials/M_Tech_Hex_Tile_Pulse.M_Tech_Hex_Tile_Pulse'"));
if (Material.Object != NULL)
{
TheMaterial = (UMaterial*)Material.Object;
}
CubeVisual->SetMaterial(0, TheMaterial);
}
The headerfile looks like this:
UCLASS()
class MYPROJECT_API ADynamicMeshSpawner : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ADynamicMeshSpawner();
// Called when the game starts or when spawned
virtual void BeginPlay() override;
// Called every frame
virtual void Tick( float DeltaSeconds ) override;
// Pointer to the material that needs to be used
UMaterial* TheMaterial;
};
The final output looked like this in the editor:
I set it up so that an instance of my class 'DynamicMeshSpawner' would be spawned everytime I hit 'P' on the keyboard. When the instance of this class is created, it calls the constructor, which spawns the cube with the material applied. I did the class instance spawning stuff in BluePrints using the SpawnActor node.
The conditions that you require for spawning stuff would obviously depend on the application.
This method works for normal Materials but NOT Material Instances. I believe you would have to make changes to the type of TheMaterial, the ConstructorHelper call, and the cast from the material reference into TheMaterial in order to make it function.
I'm confident that this would work with Animated materials as well, meaning that the 2D animations would need to be converted into a Material of some sort.
Perhaps the link below would help.
https://forums.unrealengine.com/showthread.php?6744-Flipbook-material-to-recreate-an-animated-gif
EDIT 2:
Below are a very good set of examples on how to procedurally create objects in Unreal. Leaving it here for posterity and in case anyone comes looking.
https://github.com/SiggiG/ProceduralMeshes/