How can I hide objects behind other objects in unity 2D dynamically?
Example: I have a cactus asset in my scene and want to be able to place a random number of collectibles behind the cactus, so that the collectibles are visible to the player. If possible, I also want to be able to determine the degree of visibility.
http://imgur.com/Fd2AENS
If you're using the orthographic camera, then the z axis value will not make a difference. The orthographic camera does not have any sense of depth. What you want to manipulate is the sorting layer property on the sprite renderer component.
Make all the the objects you wanna hide children of the cactus.
I assume each child has a sprite renderer component, as you are using visible 2d objects.
the order of sprites is determined with "sorting order" attribute. so here is a piece of code that gives all the other objects a lower order so they go behind the cactus.
SpriteRenderer[] renderers = GetComponentInChildren<SpriteRenderer> ();
for(int i =0 ; i< renderers.Length; i++){
renderers [i].sortingOrder = -1 * i;
}
this code changes the order of children, but if you want to make them invisible, use transform.enabled=false for each child
Related
The last few days I've been stuck with a headache of a problem in Unity.
Okay, I won't go into details with my game, but I've made a super-simple example which represents my issue.
I have a 2D scene these components:
When the scene loads, and I tap the button this script executes:
Vector3 pos = transform.position;
pos.x -= 10;
transform.position = pos;
I have also tried this code:
transform.position = Camera.main.WorldToScreenPoint(new Vector3(0, 0, 0));
The problem is, that when I click the button, the x-pos of the object sets to -1536 which is not as expected. Picture shows the scene after the button has been clicked. Notice the Rect Transform values:
So I did a little Googling and found out about ScreenToWorldPoint, WorldToScreenPoint etc but no of these conversions solves my problem.
I'm pretty sure I'm missing someting here, which probably is right in front of my, but I simply can't figure out what.
I hope someone can point me in the right direction.
Best regards.
The issue is that you are using transform.position instead of rectTransform.anchoredPosition.
While it's true that UI elements are still GameObjects and do have the normal Transform component accessible in script, what you see in the editor is a representation of the RectTransform that is built on top. This is a special inspector window for UI elements, which use the anchored positioning system so you can specify how the edges line up with their parent elements.
When you set a GameObject's transform.position, you are providing a world space position specified in 3D scene units (meters by default). This is different from a local position relative to the canvas or parent UI element, specified in reference pixels (the reference pixel size is determined by the canvas "Reference Resolution" field).
A potential issue with your use of Camera.WorldToScreenPoint is that that function returns a position specified in pixels. Whereas, as mentioned before, setting the transform.position is specified in scene units (i.e. meters by default) and not relative to the parent UI element. The inspector, though, knows it's a UI element so instead of showing you that value, it is showing you the world position translated to the UI's local coordinates.
In other words, when you set the position to zero, you are getting the indices of whatever pixels happen to be over the scene's zero point in your main camera's view, and converting those pixel numbers to meters, and moving the element there. The editor is showing you a position in reference pixels (which are not necessarily screen pixels, check your canvas setting) relative to the object's parent UI element. To verify, try tilting your camera a bit and note that the value displayed will be different.
So again you would need to use rectTransform.anchoredPosition, and you would further need to ensure that the canvas resolution is the same as your screen resolution (or do the math to account for the difference). The way the object is anchored will also matter for what the rectTransform values refer to.
Try using transform.localposition = new Vector3(0,0,0); as your button is a child of multiple game objects. You could also try using transform.TransformPoint, which should just convert localpos to worldpos.
The issue is that your button is inside of another object. You want to be changing the local position. transform.localPosition -= new Vector3(10, 0, 0)
As #Joseph has clearly explained, you have to make changes on your RectTransform for your UI components, instead of change Transform.
To achieve what you want, do it like this:
RectTransform rectTransform = this.GetComponent<RectTransform>();
Vector2 anchoredPos = rectTransform.anchoredPosition;
anchoredPos.x -= 10;
rectTransform.anchoredPosition = anchoredPos;
Just keep in mind that this 10 are not your 3D world space units (like meters or centimeters).
Try these things because I did not understand what you were trying to do
Try using transform.deltaposition
Go to the canvas and go then scale with screen size then! You can use transform.position = new Vector3(transform.position.x -10,transform.position.y, transform.positon.z)
And if this doesn't work
transform.Translate(new Vector3(transform.deltaposition.x - 10,transform.deltaposition.y, transform.deltaposition.z);
I have a better idea. Instead of changing the positions of the buttons, why not change the values that the buttons represent?
Moving Buttons
Remember that the buttons are GameObjects, and every gameobject has a position vector in its transform. So if your button is named ButtonA, then in your code you want to get a reference to that.
GameObject buttonA = GameObject.Find("ButtonA");
//or you can assign the game object from the inspector
Once you have a reference to the button, you can proceed in moving it. So let's imagine that we want to move ButtonA 10 units left.
Vector3 pos = buttonA.transform.position;
pos.X -= 10f;
buttonA.transform.position = pos;
I am trying to understand how Unity decides what to draw first in a 2D game. I could just give everything an order in layer, but I have so many objects that it would be so much easier if it was just drawing in the order of the hierarchy. I could write a script that gives every object its index, but I also want to see it in editor.
So the question is, is there an option that I can check so that it uses the order in the hierarchy window as the default sorting order?
From your last screenshot I could see you are using SpriteRenderer.
The short answer to the question "is there an option that I can check so that it uses the order in the hierarchy window as the default sorting order?" would be no, there isn't by default*.
Sprite renderers calculates which object is in front of others in one of two ways:
By using the distance to the camera, this will draw the objects closest to the camera on top of the rest of the objects in that same order in layer, as per the docs:
Sprite Sort Point
This property is only available when the Sprite Renderer’s Draw Mode is set to Simple.
In a 2D project, the Main Camera is set to Orthographic Projection mode by default. In this mode, Unity renders Sprites in the order of their their distance to the camera, along the direction of the Camera’s view.
If you want to keep everything on the same sorting layer/order in layer you can change the order in which the objects appear by moving one of the two objects further away from the camera (this is probably further down the z axis). For example if your Cashew is on z = 0, and you place the walnut on z = 1 then the cashew will be drawn on top of the walnut. If Cashew is on z=0 and the walnut is on z = -1 then the walnut will be draw on top (Since negative is closer to the camera). If both of the objects are on z - 0 they are both equally as far away from the camera, so it becomes a coin toss for which object gets drawn in front, as it does not take into account the hierarchy.
The second way the order can be changed is by creating different sorting layers, and adjusting the order in layer in the sprite renderer component. But you already figured that out.
*However, that doesn't mean it cannot be done, technically...
If you feel adventurous there is nothing stopping you from making an editor script that automates setting the order in layer for you based on the position in the hierarchy. This script would loop through all the objects in your hierarchy, grab the index of the object in the hierarchy, and assign the index to the Order in Layer.
I don't think Unity has such feature (https://docs.unity3d.com/Manual/2DSorting.html).
Usually you shall define some Sorting Layers:
far background
background
foreground
and assign Sprite Renderer of each sprite to one of Sorting Layers
I'm using Isometric Tilemap to make my game map.
I'm using unity 2018 3.5f version.
But every guide said that just use palette, but my game tilemap is a little
dynamic. So I can add, change and delete tiles in tilemap at runtime (dynamically).
And I must read the tile data from map xml files. So i can add tiles by programmatically.
In reference there is a 'setTile()' method. But there is no proper example about use this.
Should I create tile game object first and drag it to prefabs folder for make it tile prefab. And I must use like this?
setTile(position , TilePrefab.Instantiate());
May I get some example for how to use setTile to add tiles programatically.
And I'm a newbie of unity so if you mind please give more tips or advice about tilemap (just anything).
This does not seem like a "newbie" question at all. It seems fairly clear that you just want to lay down tiles programmatically rather than via the editor.
I ran in to the same question because I wanted to populate my tiles based on a terrain generator. It's surprising to me that the documentation is so lacking in this regard, and every tutorial out there seems to assume you are hand-authoring your tile layouts.
Here's what worked for me:
This first snippet does not answer your question, but here's my test code to lay down alternating tiles in a checkerboard pattern (I just have two tiles, "water" and "land")
for (int x = 0; x < 10; x++)
{
for (int y = 0; y < 10; y++)
{
Vector3Int p = new Vector3Int(x,y,0);
bool odd = (x + y) % 2 == 1;
Tile tile = odd ? water : land;
tilemap.SetTile(p, tile);
}
}
In order to get an instance of a Tile, I found that two different methods worked:
Method 1: Hook up Tiles to properties using Editor
In the MonoBehaviour class where you are writing the code to programmatically generate the tile layout, expose some public properties:
public Tile water;
public Tile land;
Then in the Unity Inspector, these fields will appear. If you press the little bullseye next to these properties it will open up a "Select Tile" window where you should be able to see any tiles that you have previously added to the Tile Palette
Method 2: Programmatically Create Tile from Texture in Resources folder
If you have a lot of different tile types, manually hooking up properties as described above may become tedious and annoying.
Also if you have some intelligent naming scheme for your tiles which you want to take advantage of in code, it will probably make more sense to use this second method. (e.g. maybe you have four variants of water and four of land that are called water_01, water_02, water_03, water_04, land_01, etc., then you could easily write some code to load all textures "water_"+n for n from 1 to numVariants).
Here's what worked for me to load and create a Tile from a 128x128 texture saved as Assets/Resources/Textures/water.png:
Tile water = new Tile();
Texture2D texture = Resources.Load<Texture2D>("Textures/water") as Texture2D;
water.sprite = Sprite.Create(texture,
new Rect(0, 0, 128, 128), // section of texture to use
new Vector2(0.5f, 0.5f), // pivot in centre
128, // pixels per unity tile grid unit
1,
SpriteMeshType.Tight,
Vector4.zero
);
I stumbled across this question a year later and had to make tweaks to uglycoyote's answer to get it to work with RuleTiles, so I thought I would post the change I had to make just in case someone else finds this answer.
The good news is that you can also implement RuleTiles this way! Instead of creating Tile properties, I had to create TileBase properties instead, like so:
public TileBase water;
public TileBase grass;
Also, in this same class, create a Tilemap property and make it public like so:
public Tilemap tileMap;
Now, go into the inspector and drag your tiles, whether they be RuleTiles or normal tiles, into the exposed tile properties, and drag the tilemap from the hierarchy view into the exposed tileMap property. This gives you a reference to that tileMap object from within this class.
From here, it's as simple as creating a for loop to populate the tilemap:
for(int x = 0; x < 10; x++) {
for(int y = 0; y < 10; y++) {
tileMap.SetTile(new Vector3Int(x, y, 0), grass);
}
}
For instance, the above will create a 10x10 map of just grass tiles, but you can do whatever you want inside the nested for loops.
I have two gameobjects at different positions in the world space. But the position values under the transform attribute shows the same value.One object is a cube and the other one is a chess piece (a prefab).Here is the screenshot of the window with the objects. I'm completely new to unity and it would so helpful if someone could help me sort this out.Thanks.The screenshot the whole window.
If none of them isn't child of other gameObjects ,then maybe pivot of chess gameObject is not in center of your mesh ,check your 3D model of chess and set its pivot to center of gameObject.
Your chess piece is certainly set as child of an object located around (X=3.5, Y=2.0, Z=4.5) coordinates. Unity displays the localPosition of Transform components.
In your print screen you have scaled one of the objects 10 times. Could it be that the anchor of that object is at 0, 0, 0 but the rendered Chess piece is then rendered with offset.
Expand your mesh renderer and see if there are any offset variables
I have a difficulty with Unity2D's Sprite rendering.
Currently I have a sprite for a gameBoard, an empty GameObject holding the spawnPoint, a random sprite marking it, as well as a playerSprite to be instantiated as a prefab. If I am just using the hierarchy on Unity, the playerSprite shows perfectly above the gameBoard, and "hard-coding" its position will always keep it above the gameBoard sprite, visible to the eye.
The problem comes when I want to instantiate the gameBoard and dynamically adding the playerPrefabs into the game.
Here is the current code snippet I am currently using:
gameBoard.SetActive(true); //gameBoard is defined as a public gameObject with its element defined in Unity as the gameBoard sprite.
Player.playerSprite = (GameObject)Instantiate(Resources.Load("playerSprite"));
Player.playerSprite.transform.localPosition = spawnPoint.transform.localPosition;
The result is that the spritePrefab spawns at the place I want perfectly, but behind the gameBoard sprite, making it hidden when the game runs.
The result is the same when using transform.position instead of transform.localPosition
How should I code the transform part. such that I can still make my playerSprite visible? Thanks.
It's most likely not an issue with the position, but rather the Sorting Order of your Sprite Renderers.
The default values for any SpriteRenderer is Layer = Default & Sorting Order = 0
Sprite Renderers with a higher sorting order are rendered on top of those with a lower value.
Add the following lines to the end of your code, and try it out.
gameBoard.GetComponent<SpriteRenderer>().sortingOrder = 0;
Player.playerSprite.GetComponent<SpriteRenderer>().sortingOrder = 0;
Obviously, you could do the same thing in the inspector as well.