Changing sprites using Sprite.Create does not take effect? - unity3d

I'm making minecraft-like 2D game and everything seems like it's okay except changing block texture in one chunk. This is how I try to change sprite:
var block = new GameObject("blok", typeof(SpriteRenderer), typeof(BoxCollider2D), typeof(CircleCollider2D));
block.GetComponent(SpriteRenderer).sprite = Sprite.Create(Resources.Load("/Prefabs/Blokovi/blok_zemlja") as Texture2D, Rect(0, 240, 16, 16), Vector2(0.5, 0.5), 16);
It does not take any effect, why?
P.S. I use UnityScript/JavaScript.
Thanks in advance!

You do not need to use Instantiate() to create new empty GameObject. You are doing this right by using only constructor. To populate the GameObject by new components try to use AddComponent() method instead of putting the types to constructor. This method returning type is Component so you can easily get reference to just added component. Small example:
var block = new GameObject("block");
block.AddComponent("BoxCollider2D");
block.AddComponent("CircleCollider2D");
var spriteRenderer = block.AddComponent("SpriteRenderer");
spriteRenderer.sprite = Sprite.Create(Resources.Load("/Prefabs/Blokovi/blok_zemlja") as Texture2D, Rect(0, 240, 16, 16), Vector2(0.5, 0.5), 16);

I solved my problem by adding an tag named "blok" to block GameObject and adding one for loop which then changes sprite for every type of block (gameobject with tag "blok"). Here is for loop code:
var go_list = GameObject.FindGameObjectsWithTag ("blok");
for (var object in go_list) {
}

Related

Unity: Add a Text Using a TextMesh Via Script?

I just want to be able to see some text rendered in the world.
The only example code that I've found is this:
GameObject Text = new GameObject();
TextMesh textMesh = Text.AddComponent<TextMesh>();
textMesh.font = new Font();
mat.SetColor("_Color", Color.black);
mat.SetPass(0);
meshRenderer.material = mat;
textMesh.text = "Hello World!";
Where mat is defined by the code:
Shader shader = Shader.Find("Hidden/Internal-Colored");
mat = new Material(shader);
mat.hideFlags = HideFlags.HideAndDontSave;
mat.SetInt("_Cull", (int)UnityEngine.Rendering.CullMode.Off);
mat.SetInt("_ZWrite", 0);
mat.SetColor("_Color", Color.blue);
mat.SetPass(0);
This code is added to the Start of MonoBevaviour. And the script is tied to Game Main camera.
No text appears anywhere that I can see.
Ah I think I might have something.
I am not sure though if this works for VR devices - I know that Unity e.g. doesn't render Screenspace overlay canvas on XR.
But back to the point: There is a legacy UI system which is usually not used anymore except for in editor Inspector scripting IMGUI
I think it might actually fit your very special need using GUILayout.Label you should be able to draw a flat label onto the screen even in VR.
With GUI.Label you have full control over the pixel coordinates and size.
public class YourTextDrawer : MonoBehaviour
{
void OnGUI()
{
var color = GUI.color;
GUI.color = Color.green;
var textPosition = new Rect(Screen.width / 2 - 150, Screen.height / 2 - 100, 300, 200);
GUI.Label(textPosition, "Hello World!");
GUI.color = color;
}
}
Not tested, just scrabbling this down from memory right now
And actually thinking about it, this might even work for your image as well

Unity how to set a prefab property trought an array

Could you please help me to write the right syntax? I am stuck with the following code:
GameObject cube = (GameObject)Instantiate(cube_prefab, new Vector3(x, y, 0), Quaternion.identity, transform);
cube.GetComponentInChildren<TextMeshPro>.text = "test" **// WORKS FINE**
Take into account that inside my prefab i have more TextMeshPro, so my question is: how can I get to the second object if i can't access trought an array ? sounds weird for me
cube.transform.GetChild(0).GetComponent<TextMeshPro>().text = "AAA" // DOESN'T WORK
Thanks in advance
The GetChild(int) method is a method of transform. In your example, you're calling GetChild(0) from the GameObject instead. So the fix in your example would use the transform property of your "cube", find the child, then get the component of the child item:
GameObject cube = (GameObject)Instantiate(cube_prefab, new Vector3(x, y, 0), Quaternion.identity, transform);
cube.GetComponentInChildren<TextMeshPro>.text = "test" **// WORKS FINE**
cube.transform.GetChild(0).GetComponent<TextMeshPro>.text = "test"
Here's the Unity docs for GetChild(int).
If you wanted to iterate over the next level of children for your game object, you could do this:
var t = cube.transform;
var childCount = t.childCount;
for ( int i = 0; i < childCount; i++ )
{
if ( t.GetChild(i).TryGetComponent<TextMeshPro> ( out var tmp ) )
{
tmp.text = $"TextMeshPro found on child {i}";
}
}
Be aware, that this will only iterate over the direct children of "cube", not the children of those children. You would have to check the child count of each child to check further down the family tree.
Sorry if I sound like I'm preaching, but it seems you just try to guess what the syntax is, without knowing what it each thing really does, and it won't do you any good. You should look into methods with generics (especially how to call them) and try to write code meaningfully instead of throwing brackets here and there, and expect things to happen.
With that out of the way, let's look at your issue.
The name 'GetChild' does not exist in the current context, because your cube is of GameObject type, which indeed doesn't have a GetChild method. The component that does have it is Transform. You should call it like: cube.transform.GetChild(0)...
If you fix that, the next issue is that GetChild method doesn't use generics (<Type>) and even if it did, first you provide should provide a type in angle brackets, and then write regular brackets () to indicate method call. What you probably wanted is to first get child, and then to get a component in it: cube.transform.GetChild(0).GetComponent<TextMeshPro>().text = "test";
In cube.GetComponentInChildren<TextMeshPro>.GetChild(0).text you miss brackets: cube.GetComponentInChildren<TextMeshPro>().GetChild(0).text. Morover, the TextMeshPro doesn't have a GetChild method, you must have confused ordering of your method calls.
In cube.GetComponentInChildren<TextMeshPro>[0] you try to use syntax as if you were using arrays, while GetComponentInChildren is just a method, not a property that is an array.
To answer your question shortly: use yourGameObject.transform.GetChild(childIndex).GetComponent<TextMeshPro>().text transform.GetChild() to navigate down to your desired gameObject and only then call GetComponent (remember brackets!) to get to your text property.
the right syntax was
cube.transform.GetChild(0).gameObject.GetComponent().text = "test"
cube.transform.GetChild(1).gameObject.GetComponent().text = "test"

Is there a way to specify where a game object spawns in the hierarchy in unity?

I have set up a random spawner that creates new game objects but they are being created outside of my canvas and therefore can't be seen when play the game. Is there any way to fix this? The objects 'neg thoughts' are UI Buttons and are being created outside of the canvas even though I need them to appear on screen so they can be used.
I did see a similar question but the suggestions didn't work for my problem.
this is very frustrating for me and any help would be awesome!
You can simply pass the parent into Instantiate
parent Parent that will be assigned to the new object
var newObj = Instantiate(prefab, parentTransform);
or with additional transforms
var newObj = Instantiate (prefab, position, rotation, parentTransform);
Or as others already said you can still do it afterwards at any time either by simply assigning a new transform.parent
newObj.transform.parent = parentTransform;
or using transform.SetParent
newObj.transform.SetParent(parentTransform, worldPositionStays);
The advantage of the later is that you have an optional parameter worldPositionStays
worldPositionStays If 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.
assigning a new
transform.parent = parentTransform;`
will always act the same way as
transform.SetParent(parentTransform);
since the default value for worldPositionStays (so if you don't explicitly pass it) is true.
So for the specific case of UI in a Canvas you could use
public TheSpawnComponent : MonoBehaviour
{
// Via the Inspector drag&drop any object here that is inside the canvas
// or the canvas itself
[SerializeField] private GameObject parentInCanvas;
[SerializeField] private Button buttonPrefab;
public void DoInstantiate()
{
var newButton = Instantiate (buttonPrefab, parentInCanvas);
//Todo Position and callback
}
}
Or if the spawner script is attached to an object inside the canvas anyway you could also spawn as child of this one directly using
var newButton = Instantiate(buttonPrefab, transform);
You can specify the transforms parent after you have created the game object.
spawnedObject.transform.parent = canvas.transform;
You have to use below code
public GameObject Prefab; // Object to Create
public Transform ParentOfObj;// Must Be inside the canvas or canvas it self
void Start()
{
GameObject g = Instantiate(Prefab) as GameObject;
g.transform.SetParent(ParentOfObj);
g.transform.localScale = Vector3.one;
}

How to make Unity UI object draggable when the objects are instantiating at runtime?

I am working on a management game where every user has some specific characters in save files. I am instantiating these characters inside a panel, I want the user to choose one of the cards and drag it to some specific point. I am able to make a drag script for the object that is already in a scene. But how to achieve the same thing if objects are generating at runtime?
I just need some idea how to do it.
here's my current code to drag UI object.
public void OnDrag(){
btn.transform.position = Input.mousePosition;
}
public void EndDrag(){
if (btn.transform.position.x -500 <50 || btn.transform.position.x -500 > -50) {
//btn.transform.position = new Vector3 (-10, 10);
rt.anchoredPosition = new Vector3 (500, 100, 0);
}
else{
rt.anchoredPosition = new Vector3 (-10, -10, 0);
}
}
At the time you Instantiate your GameObject obj, do:
obj.addComponent("YourScript");
where YourScript is your script, which you have written, that attached to a GameObjects makes it draggable..
Alternatively, you instantiate a prefab, attach the script to the prefab through the editor.
This is preferrable because addComponent() will get deprecated in the next versions.
I also recommend to keep a List<YourInstantiatedObjectType> in the parent.

Unity: GameObject always at center regardless of position changes

I am working on a 2D game and have created a game object using C# script as below. I also set my camera to orthogonal and have adjusted my sprite based on the width of the screen. Regardless of the position I set, the object is always at the center of the screen. How can I solve this?
using UnityEngine;
using System.Collections;
public class TestingPositions : MonoBehaviour {
GameObject hero;
Sprite heroSprite;
Vector3 heroPosition;
// Use this for initialization
void Start () {
hero = new GameObject ();
Instantiate (hero, heroPosition, Quaternion.identity);
Camera camera = GameObject.FindGameObjectWithTag ("MainCamera").GetComponent<Camera> ();
heroPosition = camera.ScreenToWorldPoint(new Vector3(Screen.width/4, Screen.height/4, camera.nearClipPlane));
heroSprite = Resources.Load <Sprite> ("Sprites/heroImage");
SpriteRenderer renderer = hero.AddComponent<SpriteRenderer>(); renderer.sprite = heroSprite;
}
}
when you use Instantiate you have to use it on
an existing model.
Instantiate means "duplicate this model" or "copy this model", or "make a new one, using this model as an example".
What you are doing, is creating a brand new empty "hero" game object - and then "instantiating" it. That is meaningless and does nothing.
What you must do whenever you want to use "Instantiate" is this:
public GameObject modelPerson;
Note that the name must be "modelSomething".
first put that in your code. LOOK at the Inspector. MAKE your actual model hero (or whatever it is)
Sit it somewhere off camera where it is not seen.
Now, drag that thing to the "modelPerson" slot in the Inspector.
If you are not familiar with the basics of using Inspector-dragging in Unity, review basic Unity tutorials https://unity3d.com/learn/tutorials/topics/scripting
Next in your code, perhaps in Start, try this
GameObject newHero = Instantiate( modelPerson );
newHero.transform.position = .. whatever you want
newHero.transform.rotation = .. whatever you want
newHero.name = "Dynamically created";
newHero.transform.parent = .. whatever you want
once you understand these basics, there is very much more to learn about Instantiate. You can ask that in separate questions. Good luck.
Your need to save the reference to your gameObject that is created with Instantiate, because Instantiate makes a copy not modifies the original.
To modify a gameobjects position after instantiation, you need to use gameobject.transform.position = newPosition; To modify it before instantiation, you would need to do the "heroPosition" line before using heroPosition in Instantiate.
So like this:
using UnityEngine;
using System.Collections;
public class TestingPositions : MonoBehaviour
{
GameObject hero;
SpriteRenderer heroSprite;
// Use this for initialization
void Start()
{
Camera camera = GameObject.FindGameObjectWithTag("MainCamera").GetComponent<Camera>();
//Save the reference to the instantiated object into a variable
//Since you are creating an object from scratch, you don't even need Instantiate, which means copy - not create.
hero = new GameObject();
//Set its position
hero.transform.position = camera.ScreenToWorldPoint(new Vector3(Screen.width / 4, Screen.height / 4, camera.nearClipPlane));
//Set its rotation
hero.transform.rotation = Quaternion.identity;
//Add sprite renderer, save the reference
heroSprite = hero.AddComponent<SpriteRenderer>();
//Assign the sprite
heroSprite.sprite = Resources.Load<Sprite>("Sprites/heroImage");
}
}