How to set tile in tilemap dynamically? - unity3d

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.

Related

Unity 2D Tilemap, and ever increasing Total Object Count

I'm creating a game that uses an 80x40 2D Tilemap, using procedural terrain generation. Currently, creating the map works flawlessly, as well as re-building with a button press (as many times as I want). And, I'm getting really great graphical performance (~800 of FPS).
However, I'm noticing that every time I rebuild the map, I get an increasing Total Object Count in the Profiler-memory section. The increase per map re-build is around 2500 to 2700 objects. This is not quite the full amount of tiles (3200) but is close enough that I suspect the sprite drawing as the source of the leak.
Reading online indicates that there is potentially a memory leak with the Material renderer. I'm not sure if the method I'm using to redraw the map falls within this category or not. Here's how I'm doing it...
I have a bunch of sprite atlases... for various auto-tiling terrain types. Essentially, I do the following...
Vector3Int v3 = new Vector3Int(0, 0, 0);
TerrainTile theTile = ScriptableObject.CreateInstance<TerrainTile>();
for (int x = 0; x < theWorld.Width; x++)
{
for (int y = 0; y < theWorld.Height; y++)
{
int nValue = theWorld.squares[x, y].tN_value[tType];
theTile.sprite = Terrain_atr.GetAutoTileSprite(nValue);
theTilemap.SetTile(v3, (TileBase)theTile);
}
}
GetAutoTileSprite just grabs a sprite from a sprite atlas based on an auto-tile rule.
So, does the above method of painting sprites fall into the Material renderer memory leak?
I can't find any other source of objects in my code, as I simply reuse all variables every time I rebuild the map... I'm not (as far as I can see) creating anything new.
Thanks for any insight.

Lock dimension scale of child meshes in Unity

I am building a mobile app in Unity that allows the user to scale objects in all three dimensions (currently using LeanTouch). This all works fine, but obviously when you scale the parent gameobject everything scales in that dimension. I would prefer to only allow certain meshes contained within the gameobject to actually scale, based on the dimension that is scaling.
For instance, if I have a table, and the user wants to increase the width of the object on the fly (i.e. scale in the X direction), I want the top of the unit to scale, but the thickness of the individual legs remains the same. Right now if you scale the width, the legs themselves increase in thickness.
This image illustrates the issue. As the table is scaled wider, so too are the legs. I would like for the leg B width to stay the same as Leg A, despite the table top "stretching" in the X direction.
These models are made with separate meshes for each component, so I'm not trying to do this to a single mesh.
Is there a way to indicate (or within scripts) that a mesh or gameobject can only scale in two dimensions (for instance the table legs can scale in Y and Z, but not X)? I believe this is called "Plane Locking" in Blender.
Right now I'm using Blender to import a DXF, which I'm converting to .obj or .fbx, however I'm a complete noob at it.
Thanks for any suggestions
I suggest you writing a simple script that anchors one object to another in a specific position, like this:
using UnityEngine;
using UnityEditor;
[ExecuteInEditMode, DisallowMultipleComponent]
public class Anchor : MonoBehaviour
{
public Transform target;
public Vector3 localPosition;
void Update()
{
if (target == null) return;
transform.position = target.position - transform.TransformVector(localPosition);
}
void OnDrawGizmos()
{
if (!enabled) return;
var pos = transform.TransformPoint(localPosition);
Gizmos.color = Color.red;
Gizmos.DrawSphere(pos, HandleUtility.GetHandleSize(pos) * .05f);
}
}
I also suggest you to do an object hierarchy similar to this:
It is advisable that the stretchable object and the anchored object to be siblings with a common parent.
With this, you can transform the table top as much as you want the the legs will remain attached to the position of the anchored objects (that should be childs of the strechable object). If you want a transformation to be applied to both the objects (scaling in the z direction, for example), just transform a common parent. The example is in 2D but it works for 3D too.
Two easy approaches to this problem are : unparent your gameobjects before you scale the parent (move them to a temporary parent, scale the parent and move tham back). Alternatively you can apply an inverse scale to all the children. The two are roughly equivalent. Have in mind in no case the side 'legs' of your combined object will stick to the sides, in 2D you could use RectTransform class for that, but in 3D I think you'll need some extra steps to achieve that.

Hide gameobjects dynamically in Unity 2D

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

Detect collision inside editor

I am creating an editor extension to easily create 2D and 3D levels. I can move a generator box using arrow keys and place a prefab assigned on the num keys.
The problem is I want to check that, if the prefab is already at that position, then it will either not allow another prefab to spawn there or delete the new prefab.
Any help would be appreciated.
I can think about two possible solutions, here.
The first one is by using Physics.OverlapSphere. I report the example from the Documentation:
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour {
void ExplosionDamage(Vector3 center, float radius) {
Collider[] hitColliders = Physics.OverlapSphere(center, radius);
int i = 0;
while (i < hitColliders.Length) {
hitColliders[i].SendMessage("AddDamage");
i++;
}
}
}
Basically, with this method, you check for the number of colliders that occupy the given area (the area itself is determined by a centre and a radius).
Another, more "basic" solution would be keeping a data structure (like a Map) containing the spawns' informations (like the coordinates of the already instantiated prefabs): this way, you can check directly from the Map if a prefab has been already instantiated here.
Hope this helps!

How do I map a texture to the sides of an icosahedron?

I have been trying to develop a 3D game for a long time now. I went through
this
tutorial and found that I didn't know enough to actually make the game.
I am currently trying trying to add a texture to the icosahedron (in the "Look at Basic Drawing" section) he used in the tutorial, but I cannot get the texture on more than one side. The other sides are completely invisible for no logical reason (they showed up perfectly until I added the texture).
Here are my main questions:
How do I make the texture show up properly without using a million vertices and colors to mimic the results?
How can I move the object based on a variable that I can set in other functions?
Try to think of your icosahedron as a low poly sphere. I suppose Lamarche's icosahedron has it's center at 0,0,0. Look at this tutorial, it is written for directX but it explains the general principle of sphere texture mapping http://www.mvps.org/directx/articles/spheremap.htm. I used it in my project and it works great. You move the 3D object by applying various transformation matrices. You should have something like this
glPushMatrix();
glTranslatef();
draw icosahedron;
glPopMatrix();
Here is my code snippet of how I did texCoords for a semisphere shape, based on the tutorial mentioned above
GLfloat *ellipsoidTexCrds;
Vector3D *ellipsoidNorms;
int numVerts = *numEllipsoidVerticesHandle;
ellipsoidTexCrds = calloc(numVerts * 2, sizeof(GLfloat));
ellipsoidNorms = *ellipsoidNormalsHandle;
for(int i = 0, j = 0; i < numVerts * 2; i+=2, j++)
{
ellipsoidTexCrds[i] = asin(ellipsoidNorms[j].x)/M_PI + 0.5;
ellipsoidTexCrds[i+1] = asin(ellipsoidNorms[j].y)/M_PI + 0.5;
}
I wrote this about a year and a half ago, but I can remember that I calculated my vertex normals as being equal to normalized vertices. That is possible because when you have a spherical shape centered at (0,0,0), then vertices basically describe rays from the center of the sphere. Normalize them, and you got yourself vertex normals.
And by the way if you're planning to use a 3D engine on the iPhone, use Ogre3D, it's really fast.
hope this helps :)