I am trying to write a .bvh animation exporter for c# and am using this export_bvh.py script from Blender as an example to copy.
My Unity exporter script basically stores the bone's rotations every frame when the scene is active. After the scene stops it then saves that list of euler rotations to the .bvh file.
I have managed to get the header part of the file looking ok, but I am now having trouble calculating the angles for the bones.
From my understanding, they are the compound angles by multiplying the parent's global transform matrix by the child's transform matrix and a rest position matrix. But the details are not very clear to me.
So I have done my best to examine and copy the way the matrices are multiplied in the export_bvh.py script, and even though I feel I have made some progress, I still face an issue which has been present from the very start, after importing my recorded animations, the rotations are sometimes way off and sometimes not. Which I believe (but am not certain) is due to Blender being right-handed and Unity being left-handed coordinate systems.
For example, when I start the Unity scene and begin to record the animation, I then move some of the bones in my armature (which gets recorded), then after saving the animation I go to try importing the .bvh into Blender. After inspecting the animation I notice that when a bone was rotated along multiple axes it will have strange results in the animation and some of the rotations either snap around or appear to wobble violently. But usually when rotating along a single axes it appears to move in the correct direction.
I have created this video which explains the issue better and shows some examples:
MORE DETAILS on YouTube
Here is the complete script for this project:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SimpleBVH5 : MonoBehaviour {
string bvhOutput;
public string savePath = "C:\\animations\\animation.bvh";
public int fps = 60;
Quaternion rootRotationOffset;
//ARMATURE BONES SECTION
public Transform hip;
public Transform spine;
public Transform chest;
public Transform shoulderR;
public Transform upper_armR;
public class DecoratedBone {
public Transform bone;
public DecoratedBone parent; // decorated bone parent, set in a later loop
public Vector3 rest_bone_head; // blender armature bone head position
public Matrix4x4 rest_arm_mat; // blender rest matrix (armature space)
public Matrix4x4 rest_arm_imat; // rest_arm_mat inverted
}
List<DecoratedBone> dBones;
//INITIALIZATION SECTION
void OnEnable () {
dBones = new List<DecoratedBone> ();
rootRotationOffset = hip.rotation;
int level = 0;
bvhOutput = "HIERARCHY\n";
bvhOutput += "ROOT hip\n";
var dBone = new DecoratedBone ();
dBone.bone = hip;
dBone.rest_bone_head = hip.position;
var rest_arm_mat = GetMatrix (dBone, rootRotationOffset);
dBone.rest_arm_mat = rest_arm_mat;
dBone.rest_arm_imat = rest_arm_mat.inverse;
dBones.Add (dBone);
bvhOutput += "{\n";
var offset = hip.position;
bvhOutput += "\tOFFSET " + offset.x.ToString("F6") + " " + (-offset).z.ToString("F6") + " " + offset.y.ToString("F6") + "\n";
bvhOutput += "\tCHANNELS 6 Xposition Yposition Zposition Xrotation Yrotation Zrotation\n";
var spineBone = InsertHierarchy (ref level, "spine", spine, dBone);
InsertHierarchy (ref level, "chest", chest, spineBone);
AscendLevel (ref level, chest, chest.GetChild (0), 1);
var shoulderRBone = InsertHierarchy (ref level, "shoulder.R", shoulderR, spineBone);
InsertHierarchy (ref level, "upper_arm.R", upper_armR, shoulderRBone);
AscendLevel (ref level, upper_armR, upper_armR.GetChild (0));
bvhOutput += "}\n";
bvhOutput += "MOTION\n";
bvhOutput += "Frames: 1\n";
bvhOutput += "Frame Time:\t" + (1.0f / fps).ToString("F6") + "\n";
StartCoroutine (RecordRoutine ()); // Finished building header info, Begin recording keyframes
}
void OnDestroy() {
System.IO.File.WriteAllText(savePath, bvhOutput);
print ("SAVED FILE!!!");
}
// HEADER SECTION HELPERS
DecoratedBone InsertHierarchy(ref int level, string name, Transform bone, DecoratedBone parent) {
/* Creats hierarchy header info for bones with parents */
string tabs = GetLevelTabs(level);
bvhOutput += tabs + "JOINT "+name+"\n";
bvhOutput += tabs + "{\n";
var dBone = new DecoratedBone ();
dBone.bone = bone;
dBone.parent = parent;
dBone.rest_bone_head = bone.position;
var rest_arm_mat = GetMatrix (dBone, rootRotationOffset);
dBone.rest_arm_mat = rest_arm_mat;
dBone.rest_arm_imat = rest_arm_mat.inverse;
dBones.Add (dBone); // Add bone to the list of bones (in the order it was created in the hiereachy/header).
var offset = bone.position - parent.bone.position;
bvhOutput += tabs + "\tOFFSET " + offset.x.ToString("F6") + " " + (-offset).z.ToString("F6") + " " + offset.y.ToString("F6") + "\n";
bvhOutput += tabs + "\tCHANNELS 3 Xrotation Yrotation Zrotation\n";
level++; // Increase the level in the hierarchy (increases depth in .bvh file and ensures curly braces will be added properly)
Debug.DrawLine (parent.bone.position, bone.position, Color.cyan, 10.0f); // Outline the skeleton in the viewport for debugging
return dBone;
}
string GetLevelTabs(int level) {
string tabs = "";
for (int lev = 0; lev <= level; lev++) {
tabs += "\t";
}
return tabs;
}
void EndSite(int level, Transform bone, Transform endEffector) {
string tabs = GetLevelTabs(level);
bvhOutput += tabs + "End Site\n";
bvhOutput += tabs + "{\n";
var offset = endEffector.position - bone.position;
bvhOutput += tabs + "\tOFFSET " + offset.x.ToString("F6") + " " + (-offset).z.ToString("F6") + " " + offset.y.ToString("F6") + "\n"; // 1 0 0\n";
bvhOutput += tabs + "}\n";
Debug.DrawRay (bone.position, offset, Color.cyan, 10.0f);
}
void AscendLevel (ref int level, Transform bone, Transform endEffector, int stopLevel = 0) {
EndSite (level, bone, endEffector);
for (int lev = level; lev > stopLevel; lev--) {
for (int tab = 0; tab < lev; tab++) {
bvhOutput += "\t";
}
bvhOutput += "}\n";
}
level = stopLevel;
}
//RECORDED MOTION SECTION
IEnumerator RecordRoutine () {
/*A simplified re-write of Blender's export_bvh.py script https://github.com/sftd/blender-addons/blob/master/io_anim_bvh/export_bvh.py*/
string line; // The string used to build each line of data.
float time = Time.time;
float interval = 1.0f / fps; // The record frame interval.
while (isActiveAndEnabled) { // Runs while the scene is actively running.
yield return new WaitUntil (() => (Time.time - time) >= interval); // Wait for desired time interval.
time = Time.time; // Reset the timer.
yield return new WaitForEndOfFrame (); // Wait for all transforms to be updated.
line = ""; // Clear the line data and prepare for next line of data.
//First do calculations for the root (hip) bone.
var p = dBones[0].rest_bone_head;
var trans = Matrix4x4.Translate (p);
var itrans = Matrix4x4.Translate (-p);
var pose_mat = GetMatrix(dBones [0], rootRotationOffset);
var rest_arm_imat = dBones [0].rest_arm_imat;
var mat_final = pose_mat * rest_arm_imat;
mat_final = itrans * mat_final * trans;
var loc = mat_final.GetPosition () ;
var rot = mat_final.GetRotation ().eulerAngles;
line += // Add root's (hip bone) data to the line of data.
(-loc.x).ToString("F6") + " " + //Output location of root bone
(-loc.z).ToString("F6") + " " +
(loc.y).ToString("F6") + " " +
(rot.x).ToString("F6") + " " + //Output rotation of root bone
(rot.z).ToString("F6") + " " +
(-rot.y).ToString("F6") + " ";
// Now do calculations for each child bone
for (int i = 1; i < dBones.Count; i++) {
p = dBones [i].rest_bone_head;
trans = Matrix4x4.Translate (p);
itrans = Matrix4x4.Translate (-p);
mat_final =
dBones [i].parent.rest_arm_mat * GetMatrix(dBones [i].parent).inverse *
GetMatrix(dBones [i]) * dBones [i].rest_arm_imat;
mat_final = itrans * mat_final * trans;
//loc = mat_final.GetPosition () + (trackedObjects [i].rest_bone_head - trackedObjects [i].parent.rest_bone_head); //Position is not required for non-root bones
rot = mat_final.GetRotation ().eulerAngles;
line += // Add children's data to the line of data.
(rot.x).ToString("F6") + " " + //Output rotation of child bone
(rot.z).ToString("F6") + " " +
(-rot.y).ToString("F6") + " ";
}
line += "\n"; // Done adding line.
if (Application.isPlaying) {
bvhOutput += line; // Add the data to the file's contents only if the scene is actively running.
}
}
}
Matrix4x4 GetMatrix (DecoratedBone dBone, Quaternion offsetRotation = default(Quaternion)) {
//return trackedObject.obj.localToWorldMatrix;
return Matrix4x4.TRS(
dBone.bone.position,
offsetRotation.Equals(default(Quaternion)) ? dBone.bone.rotation : dBone.bone.rotation * offsetRotation, //the offsetRotation (aka hip.rotation) should be applied to all bones with parents.
Vector3.one
);
}
}
Thanks for anyone who can help!
Related
Okay so im trying to implement physics into my Game, tho everything works it looks like there is no collision on the objects :(
Here is a video of whats going on: https://streamable.com/w5h4vd
My Code is pretty simple:
I have this function for setting the scene:
settingScene = true;
foreach (GameObject go in scene.GameObjects)
{
var extent = go.renderer.Mesh.Extent;
Debug.WriteLine("Extent Min: " + extent.Min);
Debug.WriteLine("Extent Max: " + extent.Max);
Debug.WriteLine("Extent Center: " + extent.Center);
CollisionShape shape;
List<Vector3> vertices = new List<Vector3>();
List<int> indices = new List<int>();
indices.AddRange((from v in go.renderer.Mesh.IndexBuffers[0]
select (int)v));
vertices.AddRange((from v in go.renderer.Mesh.VertexBuffers[0]
select v.Position - extent.Center));
Debug.WriteLine("Vertex Count: " + vertices.Count);
Debug.WriteLine("Index Count: " + indices.Count);
shape = new BvhTriangleMeshShape(new TriangleIndexVertexArray(indices.ToArray(), vertices.ToArray()), true);
Debug.WriteLine("Shape Convex: " + shape.IsConvex);
go.renderer.World = Matrix.Identity;
var body = new RigidBody(
new RigidBodyConstructionInfo(
go.Weight,
new SMotionState(go),
shape, shape.CalculateLocalInertia(go.Weight)));
Debug.WriteLine("Body Shape Scaling: " + body.CollisionShape.LocalScaling);
if (body.IsStaticObject)
{
body.Restitution = go.Restitution;
body.Friction = go.Friction;
}
go.body = body;
world.AddRigidBody(body);
}
settingScene = false;
The scene class is only a list of GameObjects, which store Position rotation and scale.
I use this for stepping the sim:
if (settingScene) return;
if ((float)simTime.Elapsed.TotalSeconds < time)
{
time = 0;
timeStep = 0;
}
timeStep = ((float)simTime.Elapsed.TotalSeconds - time);
time = (float)simTime.Elapsed.TotalSeconds;
world.StepSimulation(timeStep, 7);
and i use this for initialisation:
simTime.Start();
time = 0f;
timeStep = 0f;
world = new DiscreteDynamicsWorld(dispatcher, broadphase, solver, conf);
world.Gravity = new Vector3(0f, -9.81f, 0f);
All Variables:
static DynamicsWorld world;
static CollisionConfiguration conf = new DefaultCollisionConfiguration();
static ConstraintSolver solver = new SequentialImpulseConstraintSolver();
static Dispatcher dispatcher = new CollisionDispatcher(conf);
static BroadphaseInterface broadphase = new DbvtBroadphase();
static Stopwatch simTime = new Stopwatch();
static float time, timeStep;
static bool settingScene = false;
What am i doing wrong?
Why do the cube not have collision?
I got a step further: it detects collision when doing rig.CheckCollideWith but it doesnt do anything else with collision
I have tried:
Printing all the values from the body and GameObject to see if there is any problem
Hard coding the values
Any help will be greatly appreciated!
I'm having a problem with an accumulation of Point3ds in List. When I change the number of int agents (via a gui slider in grasshopper) the quantity keeps increasing rather than resetting to whatever the new quantity should be. I'm guessing that somewhere I should be re-initializing the list or clearing it everytime the value is changed? What would be the correct to do this?
protected override void SolveInstance(IGH_DataAccess DA)
{
BoundingBox box = new BoundingBox(0.0, 0.0, 0.0, boundx, boundy, boundz);
DA.SetData("Bounding Box", box);
DA.SetData("Start", "The current trigger is set to " + started.ToString());
// Initialize Agents
for (int i = 0; i < agents; i++)
{
double xPos = RandomfromDouble(0.0, boundx);
double yPos = RandomfromDouble(0.0, boundy);
double zPos = RandomfromDouble(0.0, boundz);
Point3d pos = new Point3d(xPos, yPos, zPos); // Create Agent Start Position
Vector3d vec = new Vector3d(xPos + RandomfromDouble(-360.00, 360.00), yPos + RandomfromDouble(-360.00, 360.00), zPos + RandomfromDouble(-360.00, 360.00)); // Create Agent Start Vector
Agent agent = new Agent(pos, vec, alignment, separation, cohesion, neighborRadius);
allAgents.Add(agent);
DA.SetData("Debug", "# of Agents Created: " + allAgents.Count);
}
// Get agent positions
List<Point3d> agentPositions = new List<Point3d>();
List<Vector3d> agentVectors = new List<Vector3d>();
agentPositions = allAgents.Select(agent => agent.Pos).ToList();
agentVectors = allAgents.Select(agent => agent.Vec).ToList();
DA.SetData("Agent Count", allAgents.Count);
DA.SetDataList("Agent Points", agentPositions);
DA.SetDataList("Agent Vectors", agentVectors);
if (started)
{
DA.SetData("Start", "The current trigger is set to " + started.ToString());
for (int i = 0; i < generations; i++)
{
DA.SetData("Debug", "# of Generations: " + i);
foreach (Agent agent in allAgents)
{
DA.SetData("Debug", "# of Agents: " + i);
agent.UpdateAgent(allAgents);
}
}
}
else if (!started)
{
DA.SetData("Start", "The current trigger is set to " + started.ToString());
//return;
}
}
public double RandomfromDouble(double from, double to)
{
double diff = Math.Abs(from - to);
return rnd.NextDouble() * diff + from ;
}
If I'm reading your code correctly, your issue is that the allAgents list keeps getting longer. As you guessed, that's because you're creating the list once, at the top, and then you only ever add to it, within the for loop that says // Initialize Agents.
If your intent is to reset the list at this point, then before you enter the for loop I think you need to do allAgents.Clear(). This will empty the list, and then you loop through and add the new Agents within the loop.
If the grid is 10x10 or 23x7 it's working fine but when the grid have 1.5 spaces between the cubes the directions sometimes are wrong.
This is the grid script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GridGenerator : MonoBehaviour
{
public GameObject gridBlock;
public int gridWidth = 10;
public int gridHeight = 10;
public GameObject[] allBlocks;
private GameObject[] wallsParents = new GameObject[4];
void Start()
{
wallsParents[0] = GameObject.Find("Top Wall");
wallsParents[1] = GameObject.Find("Left Wall");
wallsParents[2] = GameObject.Find("Right Wall");
wallsParents[3] = GameObject.Find("Bottom Wall");
GenerateGrid();
allBlocks = GameObject.FindGameObjectsWithTag("Blocks");
var findpath = GetComponent<PathFinder>();
findpath.FindPath();
}
public void AutoGenerateGrid()
{
allBlocks = GameObject.FindGameObjectsWithTag("Blocks");
for (int i = 0; i < allBlocks.Length; i++)
{
DestroyImmediate(allBlocks[i]);
}
var end = GameObject.FindGameObjectWithTag("End");
DestroyImmediate(end);
GenerateGrid();
allBlocks = GameObject.FindGameObjectsWithTag("Blocks");
var findpath = GetComponent<PathFinder>();
findpath.FindPath();
}
public void GenerateGrid()
{
for (int x = 0; x < gridWidth; x++)
{
for (int z = 0; z < gridHeight; z++)
{
GameObject block = Instantiate(gridBlock, Vector3.zero, gridBlock.transform.rotation) as GameObject;
block.transform.parent = transform;
block.transform.name = "Block";
block.transform.tag = "Blocks";
block.transform.localPosition = new Vector3(x * 1.5f, 0, z * 1.5f);
block.GetComponent<Renderer>().material.color = new Color(241, 255, 0, 255);
if (x == 0)//TOP
{
block.transform.parent = wallsParents[0].transform;
block.transform.name = "TopWall";
block.transform.tag = "Blocks";
}
else if (z == 0)//LEFT
{
block.transform.parent = wallsParents[1].transform;
block.transform.name = "LeftWall";
block.transform.tag = "Blocks";
}
else if (z == gridHeight - 1)//RIGHT
{
block.transform.parent = wallsParents[2].transform;
block.transform.name = "RightWall";
block.transform.tag = "Blocks";
}
else if (x == gridWidth - 1)//BOTTOM
{
block.transform.parent = wallsParents[3].transform;
block.transform.name = "BottomWall";
block.transform.tag = "Blocks";
}
}
}
}
}
On this line i'm adding the spaces between the cubes:
block.transform.localPosition = new Vector3(x * 1.5f, 0, z * 1.5f);
Then in another script i'm trying to find what directions next are possible to move to.
private void Directions()
{
GridGenerator gridgenerator = GetComponent<GridGenerator>();
Vector3 playerPosition;
playerPosition = player.localPosition;
if (playerPosition.x > 0)
{
// can go left
possibleDirections[0] = "Can go left";
}
else
{
possibleDirections[0] = "Can't go left";
}
if (playerPosition.x + 1 < gridgenerator.gridWidth * 1.5f)
{
// can go right
possibleDirections[1] = "Can go right";
}
else
{
possibleDirections[1] = "Can't go right";
}
if (playerPosition.z > 0)
{
// can go backward
possibleDirections[2] = "Can go backward";
}
else
{
possibleDirections[2] = "Can't go backward";
}
if (playerPosition.z + 1 < gridgenerator.gridHeight * 1.5f)
{
// can go backward
possibleDirections[3] = "Can go forward";
}
else
{
possibleDirections[3] = "Can't go forward";
}
}
possibleDirections is array string type
When the grid size is 10x10 without spaces between cubes this two lines:
if (playerPosition.x + 1 < gridgenerator.gridWidth * 1.5f)
if (playerPosition.z + 1 < gridgenerator.gridHeight * 1.5f)
Was:
if (playerPosition.x + 1 < gridgenerator.gridWidth)
if (playerPosition.z + 1 < gridgenerator.gridHeight)
But when i added the spaces between the cubes i tried to add to the gridgenerator.gridWidth and gridgenerator.gridHeight the * 1.5
But it didn't work so i tried also:
if (playerPosition.x + 1 < gridgenerator.gridWidth * (1 + 1.5))
if (playerPosition.z + 1 < gridgenerator.gridHeight * (1 + 1.5))
1 is the cube width and 1.5 is the space. But this is not working good either.
In the screenshot the player is in the top left corner facing up(forward)
He can't move forward but in the inspector it says "Can go forward" And should be "Can't go forward"
It only happens when there are spaces between the cubes.
This line is wrong:
if (playerPosition.x + 1 < gridgenerator.gridWidth * 1.5f)
Your gridWidth variable stores the number of cubes, not their collective spacing. You have 10 cubes representing move spaces, determining the out-of-bounds this value should remain constant (it's still only 10 cubes, even if they're spaced with a half-block worth of space between them).
You need to convert from the player's scene location (transform.position.x) to a board space location (likely dividing by the same multiplier used to space the cubes out).
Alternatively, the "this makes my soul cry" solution of doing this:
if (playerPosition.x + 1.5f < gridgenerator.gridWidth * 1.5f)
Because the next cube is 1.5 scene units away, not 1. And this makes my soul cry because it makes your code full of hard-coded 1.5f multipliers and offsets rather than keeping such things to a single, fixed, constant value stored Elsewhere and used sparingly.
Related:
possibleDirections[0] = "Can go left";
Why are you using stringly typed things? There are values called booleans for a reason...
I'm new to unity and I've developing a simple 2d game.
at scoreboard scene i've managed to save scores and display them on a scrollview. when i run it in unity it works fine but when i build and run in my android phone the scrollview looks a bit bigger and text ui (added by script) look very small.
Here is the code to display scores in content game object in scrollview :
void Start () {
if (PlayerPrefs.HasKey (0 + "HScore")) {
float y = -30;
for (int i = 0; i < 10; i++) {
if (PlayerPrefs.GetInt (i + "HScore") == 0) {
break;
}
GameObject textobj = new GameObject (i + "HScoreName", typeof(RectTransform));
GameObject textobj2 = new GameObject (i + "HScore", typeof(RectTransform));
Text name = textobj.AddComponent<Text> ();
Text score = textobj2.AddComponent<Text> ();
GameObject lineObj = new GameObject ("Line", typeof(RectTransform));
Image l = lineObj.AddComponent<Image> ();
l.color = Color.white;
lineObj.transform.localScale = new Vector3 (500, 0.01f, 1);
name.text = "#" + (i + 1) + "- " + PlayerPrefs.GetString (i + "HScoreName");
score.text = PlayerPrefs.GetInt (i + "HScore").ToString ();
name.color = Color.white;
score.color = Color.white;
name.alignment = TextAnchor.MiddleLeft;
score.alignment = TextAnchor.MiddleLeft;
name.horizontalOverflow = HorizontalWrapMode.Overflow;
name.font = Resources.GetBuiltinResource<Font> ("Arial.ttf");
score.font = Resources.GetBuiltinResource<Font> ("Arial.ttf");
name.fontSize = 15;
score.fontSize = 15;
score.fontStyle = FontStyle.Bold;
textobj.transform.position = content.transform.position + new Vector3 (70, y, 0);
textobj.transform.SetParent (content.transform);
textobj2.transform.position = content.transform.position + new Vector3 (180, y, 0);
textobj2.transform.SetParent (content.transform);
lineObj.transform.position = content.transform.position + new Vector3 (60, y - 25, 0);
lineObj.transform.SetParent (content.transform);
y = y - 50;
}
}
}
is there anything missing in this script to keep text fit with screen?
You are using flat numbers, what you need s a percentage of Screen.width and Screen.height
For example if you are running in a phone with resolution 150x150 for example, if you want it in position 5, 5 you write this
transform.position = (5 / 100) * 150, it will set your object at 5 PERCENT from the bottom left edge.
There is a component - Canvas Scaler on the Canvas. Try to to change UI Scale Mode - Scale with Screen Size - it must be on the Canvas. And also you can play with Math value
Try to change UI Scale Mode - Scale with Screen Size - it must be on the Canvas.
I am adding some objects in the game but for same reason, the first object I add from a generic list do not change in localScale.
As you can see from the image below, the console displays that localScale is correct, but when you look at the gameview and inspector, the object has a Vector.zero localScale. What's weird is that all the other properties of the object is correct (i.e. object.name is correctly name 3, 7).
The objects after the first are all displayed correctly as well.
Update: If I don't use Queue<GameObject> tile = new Queue<GameObject>(), things work normally..
Here's the script:
public void animateGrid(List<int[]> matchTile, List<int[]> moveTile, List<int[]> appendTile){
animating = true;
Queue<GameObject> tile = new Queue<GameObject>();
Debug.Log ("MatchTile count: " + matchTile.Count);
Debug.Log ("AddTile count: " + appendTile.Count);
foreach(int[] i in matchTile){
tile.Enqueue(getGameObject(i[0], i[1]));
match (tile.Peek());
}
Debug.Log ("tile: " + tile.Count);
foreach(int[] j in appendTile){
int x1 = j[0], y1 = j[1],
x2 = j[2], y2 = j[3];
GameObject gameObj = tile.Dequeue();
Debug.Log ("tileNo");
append ( gameObj,
getCoordinateFromGrid(x2, y2),
x2, y2,
grid.filled[x1, y1]
);
}
...
}
private void match(GameObject tile){
Hashtable optional = new Hashtable();
optional.Add("ease", LeanTweenType.easeInBounce);
LeanTween.scale(tile, Vector3.zero, 0.05f, optional);
tile.SetActive(false);
}
private void append(GameObject tile, Vector3 position, int x, int y, int type){
float tileSize = 1f / 9f;
tile.renderer.material.color = getColor(type);
tile.tag = getType(type);
tile.name = x + "," + y;
tile.transform.parent = transform.FindChild("Filled").transform;
tile.transform.position = position;
tile.transform.localScale = new Vector3(tileSize, tileSize, 70f);
tile.SetActive(true);
Debug.Log ("added scale: " + tile.transform.localScale + " x:" + x + " y:" + y);
}
If I don't use Queue tile = new Queue(), things work normally. I think its a bug.