Getting the correct position of an instantiated prefab - unity3d

When my game starts, I'm instantiating a prefab several times:
for (int y = 0; y < gridY; y++) {
for (int x = 0; x < gridX; x++) {
Vector3 pos = new Vector3 (x, 0, y) * spacing;
Instantiate(prefab, pos, Quaternion.identity);
}
}
This works fine - the objects are displayed correctly in the scene.
The prefab got a script attached, which prints the objects position to the debug output when you right click it. The problem I'm facing is that all these prefabs are returning the same position?
--edit
This is the code I use to print the coordinates:
if (Input.GetMouseButtonDown(1)) {
Debug.Log(transform.position.ToString());
}

Related

Unity: SetPixal on a texture at mouse position (2D)

I am trying to draw on a texture but I don't know the math to convert my mouse position to the texture position.
Currently, the code will draw on the texture but the coordinates are very off.
If someone can help me with this I would appreciate it.
var mousePosition = Input.mousePosition;
var drawPosition = new Vector2(mousePosition.x, mousePosition.y);
for (int x = 0; x < brushSize; x++)
{
for (int y = 0; y < brushSize; y++)
{
m_Texture.SetPixel(x + (int)drawPosition.x, y + (int)drawPosition.y, Color.clear);
}
}
m_Texture.Apply();
Try this:
Vector2 pos;
void Update(){
RectTransformUtility.ScreenPointToLocalPointInRectangle(
parentCanvas.transform as RectTransform, Input.mousePosition,
parentCanvas.worldCamera,
out pos);
}
Assign the parentCanvas and use the pos.x and pos.y inside your for loops

Unity Mesh UV problem on the positive and negative x-axis on perpendicular walls

I am trying to make a 3D-voxel game that uses the marching cubes algorithm to procedurally generate a game world. This is working fine so far, except that, on exactly perpendicular sides on the positive and negative x sides of a given perpendicular piece of the world/chunk mesh, it looks like the uv coordinates aren't quite right as it just displays a solid color instead of the texture. [![view of debug-chunks and the buggy sides][1]][1]
At <2.> you can see the chunk wall how it is supposed to look like and at <1.> you can see the weird bug. This ONLY occurs on exactly perpendicular x-side triangles! Those meshes in the image are debug-chunks to show the problem.
All the noise-to-terrain translation works fine and I don't get any bugs there. It's only the uvs that cause problems.
I am using the following code to populate the Mesh.vertices, Mesh.triangles and Mesh.uv:
void MakeChunkMeshData()
{
for (int x = 0; x < Variables.chunkSize.x - 1; x++)
{
for (int y = 0; y < Variables.chunkSize.y - 1; y++)
{
for (int z = 0; z < Variables.chunkSize.z - 1; z++)
{
byte[] cubeCornerSolidityValues = new byte[8]{
chunkMapSolidity[x, y, z],
chunkMapSolidity[x + 1, y, z],
chunkMapSolidity[x + 1, y + 1, z],
chunkMapSolidity[x, y + 1, z],
chunkMapSolidity[x, y, z + 1],
chunkMapSolidity[x + 1, y, z + 1],
chunkMapSolidity[x + 1, y + 1, z + 1],
chunkMapSolidity[x, y + 1, z + 1]
};
MarchOne(new Vector3Int(x, y, z), cubeCornerSolidityValues);
}
}
}
}
void DrawChunk()
{
chunkMesh.vertices = vertices.ToArray();
chunkMesh.triangles = triangles.ToArray();
chunkMesh.SetUVs(0, uvs.ToArray());
chunkMesh.RecalculateNormals();
}
void ClearMesh()
{
chunkMesh.Clear();
}
void ClearChunkMeshAndData()
{
chunkMesh.Clear();
uvs = new List<Vector2>();
vertices = new List<Vector3>();
triangles = new List<int>();
}
/// <summary>
/// cube contains bytes for each corner of the cube
/// </summary>
/// <param name="cube"></param>
/// <returns></returns>
int GetCubeConfiguration(byte[] cube)
{
int u = 0;
int result = 0;
for(int corner = 0; corner < 8; corner++)
{
if (cube[corner] < Variables.solidityThreshold)
{
u++;
result |= 1 << corner;
}
}
return result;
}
Vector2[] getUvsPerTriangle(byte[] voxelTypes)
{
int resId = voxelTypes[0];
if (voxelTypes[1] == voxelTypes[2])
resId = voxelTypes[1];
resId = 1;
Vector2 normalized = getUvCoordFromTextureIndex(resId) / Constants.TextureAtlasSizeTextures;
float textureLength = 1f/Constants.TextureAtlasSizeTextures;
Vector2[] result = new Vector2[3] {
normalized + new Vector2(1,0) * textureLength,
normalized + new Vector2(0,1) * textureLength,
normalized + new Vector2(1,1) * textureLength
};
//Debug.Log(result);
return result;
}
/// <summary>
/// returns the absolute x and y coordinates of the given texture in the atlas (example: [4, 1])
/// </summary>
/// <param name="textureIndex"></param>
/// <returns></returns>
Vector2 getUvCoordFromTextureIndex(int textureIndex)
{
int x = textureIndex % Constants.TextureAtlasSizeTextures;
int y = (textureIndex - x) / Constants.TextureAtlasSizeTextures;
return new Vector2(x, y);
}
/// <summary>
/// takes the chunk-wide mesh data and adds its results after marching one cube to it.
/// </summary>
/// <returns></returns>
void MarchOne(Vector3Int offset, byte[] cube)
{
int configuration = GetCubeConfiguration(cube);
byte[] voxelTypes = new byte[3];
int edge = 0;
for (int i = 0; i < 5; i++) //loop at max 5 times (max number of triangles in one cube config)
{
for(int v = 0; v < 3; v++) // loop 3 times through shit(count of vertices in a TRIangle, who would have thought...)
{
int cornerIndex = VoxelData.TriangleTable[configuration, edge];
if (cornerIndex == -1) // indicates the end of the list of vertices/triangles
return;
Vector3 vertex1 = lwTo.Vec3(VoxelData.EdgeTable[cornerIndex, 0]) + offset;
Vector3 vertex2 = lwTo.Vec3(VoxelData.EdgeTable[cornerIndex, 1]) + offset;
Vector3Int vertexIndex1 = lwTo.Vec3Int(VoxelData.EdgeTable[cornerIndex, 0]) + offset;
Vector3Int vertexIndex2 = lwTo.Vec3Int(VoxelData.EdgeTable[cornerIndex, 1]) + offset;
Vector3 vertexPosition;
if (Variables.badGraphics)
{
vertexPosition = (vertex1 + vertex2) / 2f;
}
else
{
// currently using this "profile"
// this code determines the position of the vertices per triangle based on the value in chunkSolidityMap[,,]
float vert1Solidity = chunkMapSolidity[vertexIndex1.x, vertexIndex1.y, vertexIndex1.z];
float vert2Solidity = chunkMapSolidity[vertexIndex2.x, vertexIndex2.y, vertexIndex2.z];
float difference = vert2Solidity - vert1Solidity;
difference = (Variables.solidityThreshold - vert1Solidity) / difference;
vertexPosition = vertex1 + ((vertex2 - vertex1) * difference);
}
vertices.Add(vertexPosition);
triangles.Add(vertices.Count - 1);
voxelTypes[v] = chunkMapVoxelTypes[vertexIndex1.x, vertexIndex1.y, vertexIndex1.z];
edge++;
}
uvs.AddRange(getUvsPerTriangle(voxelTypes));
}
}
EDIT:
when only slightly rotating the chunks, the weird problem immediately disappears. I don't know why, but at least i now have some clue what's going on here.
[1]: https://i.stack.imgur.com/kYnkl.jpg
Well, it turns out that this probably is some weird behavior from unity. When explicitly setting the mesh after the mesh population process as the meshFilters' mesh, it works just fine. Also, I had to call mesh.RecalculateTangents() to make it work.

Object with many children does not show up in the middle although it has coordinates set to 0, 0, 0

I am doing a Rubik cube generator with unity. Each of the pieces are basically a 1x1 cube which will be repeated in the shape of a bigger cube in my code as children of an empty object. The empty object is in the exact middle of the pieces, and all the pieces have their origins in the exact middle. However, when I put the empty to the center of the scene (0, 0, 0) It shows up in a different place.
Here are some pictures from the editor:
As you can see, the empty is in the center with coordinates set to 0, 0, 0
Now ,when it has children and the coordinates are all still 0, it shows in a different place
Edit:
#derHugo helped me out, but now my code that creates the cubes and sets the empty object to the middle of them does not work.
Here is the full code:
public GameObject PiecePrefab;
public int CubeSize;
Vector3 avg;
Vector3 ijk;
int cubeCount = 0;
// Start is called before the first frame update
void Start()
{
//Vector3 orgpos = gameObject.transform.position;
if (CubeSize <= 0)
{
CubeSize = 1;
Debug.LogError("The cube can not be smaller than 1!");
}
else if (CubeSize > 30)
{
CubeSize = 30;
Debug.LogError("The cube should not be bigger than 30!");
}
avg = new Vector3(0, 0, 0);
for (float k = 0; k < CubeSize; k++)
{
for (float j = 0; j < CubeSize; j++)
{
for (float i = 0; i < CubeSize; i++)
{
if (i == CubeSize - 1 || i == 0)
{
CreatePiece(i, j, k);
}
else if (j == CubeSize - 1 || j == 0)
{
CreatePiece(i, j, k);
}
else if (k == CubeSize - 1 || k == 0)
{
CreatePiece(i, j, k);
}
}
}
}
avg /= cubeCount;
gameObject.transform.position = avg;
var _Go = GameObject.FindGameObjectsWithTag("KuutionPala");
foreach (GameObject KuutionPala in _Go)
{
KuutionPala.transform.SetParent(transform);
}
//gameObject.transform.localPosition = orgpos;
void CreatePiece(float x, float y, float z)
{
ijk = new Vector3(x, y, z);
avg += ijk;
cubeCount++;
Vector3 offset3D;
offset3D = new Vector3(x / CubeSize, y / CubeSize, z / CubeSize);
var Piece = Instantiate(PiecePrefab, offset3D, transform.rotation);
Piece.transform.localScale /= CubeSize;
//Debug.LogFormat("x:" + x);
//Debug.LogFormat("y:" + y);
//Debug.LogFormat("z:" + z);
}
}
}
I think the error is on this row:
gameObject.transform.position = avg;
(Sorry if bad code)
As said there are two pivot modes in Unity (see Positioning GameObjects → Gizmo handle position toggles)
Pivot: positions the Gizmo at the actual pivot point of the GameObject, as defined by the Transform component.
Center: positions the Gizmo at a (geometrical) center position based on the selected GameObjects.
Yours is set to Center so in order to change that click on the button that says Center.
Then to your code
You are currently just hoping/assuming that your parent is correctly placed on 0,0,0.
Then you spawn all tiles in a range from 0 to (CubeSize - 1)/2 and then want to shift the center back.
I would rather go the other way round and calculate the correct local offset beforehand and directly spawn the tiles as children of the root with the correct offset. Into positive and negative direction.
Step 1: What is that local position?
For figuring the general maths out just look at two examples.
Let's say you have 3 cubes with indices 0,1,2. They have extends of 1/3 so actually there positions would need to look like
-0.5 0 0.5
| . | . | . |
Let's say you have 4 cubes with indices 0,1,2,3 and extends 1/4 then the positions would need to look like
-0.5 0 0.5
| . | . | . | . |
So as you can see the simplest way to go would be
start with the minimum position (e.g. -0.5f * Vector3.one)
always add half of the extends for the first offset (e.g. 1/CubeSize * 0.5f * Vector3.one)
add an offsets of the extends multiplied by the indices on top (e.g. 1/CubeSize * new Vector3(x,y,z))
so together something like
// be sure to cast to float here otherwise you get rounded ints
var extends = 1 / (float)CubeSize;
var offset = (-0.5f + extends * 0.5f) * Vector3.one + extends * new Vector3(x,y,z);
Step 2: Directly spawn as children with correct offset
void CreatePiece(float x, float y, float z)
{
var extends = 1 / (float)CubeSize;
var offset = (-0.5f + extends * 0.5f) * Vector3.one + extends * new Vector3(x,y,z);
var Piece = Instantiate(PiecePrefab, transform, false);
// This basically equals doing something like
//var Piece = Instantiate(PiecePrefab, transform.position, transform.rotation, transform);
Piece.transform.localPosition = offset;
Piece.transform.localScale = extends * Vector3.one;
}
Then you can reduce your code to
// Use a range so you directly clamp the value in the Inspector
[Range(1,30)]
public int CubeSize = 3;
// Start is called before the first frame update
void Start()
{
UpdateTiles();
}
// Using this you can already test the method without entering playmode
// via the context menu of the component
[ContextMenu(nameof(UpdateTiles)])
public void UpdateTiles()
{
// Destroy current children before spawning the new ones
foreach(var child in GetComponentsInChildren<Transform>().Where(child => child != transform)
{
if(!child) continue;
if(Application.isPlaying)
{
Destroy(child.gameObject);
}
else
{
DestroyImmediate(child.gameObject);
}
}
if (CubeSize < 1)
{
CubeSize = 1;
Debug.LogError("The cube can not be smaller than 1!");
}
else if (CubeSize > 30)
{
CubeSize = 30;
Debug.LogError("The cube should not be bigger than 30!");
}
// For making things easier to read I would use x,y,z here as well ;)
for (float x = 0; x < CubeSize; x++)
{
for (float y = 0; y < CubeSize; y++)
{
for (float z = 0; z < CubeSize; z++)
{
if (x == CubeSize - 1 || x == 0)
{
CreatePiece(x, y, z);
}
else if (y == CubeSize - 1 || y == 0)
{
CreatePiece(x, y, z);
}
else if (z == CubeSize - 1 || z == 0)
{
CreatePiece(x, y, z);
}
}
}
}
}
private void CreatePiece(float x, float y, float z)
{
var extends = 1 / (float)CubeSize;
var offset = (-0.5f + extends * 0.5f) * Vector3.one + extends * new Vector3(x,y,z);
var Piece = Instantiate(PiecePrefab, transform, false);
Piece.transform.localPosition = offset;
Piece.transform.localScale = extends * Vector3.one;
}

Two different classes with random values have the same output

I am making the Bouncing Ball using Processing. It works fine when I use the ball object once, but when I use it twice like ball1 & ball2, the balls appear on top of each other making the delusion that it is just one ball bouncing, although I'm setting their primary location and velocity a random number. So, where is the problem? (first argument is for velocity and the second is for x Coordinate)
Main class:
Ball ball1 = new Ball(int(random(0, 2)),int(random(width)));
Ball ball2 = new Ball(int(random(0, 2)),int(random(width)));
void setup() {
// Windows configurations
size(640, 360);
background(50);
}
void draw() {
// Draw the circle
ball1.display();
// Circle movements
ball1.movements();
// Movement limits
ball1.movementLimits();
// Draw the circle
ball2.display();
// Circle movements
ball2.movements();
// Movement limits
ball2.movementLimits();
}
Ball class:
float xCoordinates;
float yCoordinates;
float xVelocity;
float yVelocity;
final float gravity = 0.1;
class Ball {
Ball(int Velocity, int Coordinates) {
xCoordinates = Coordinates;
yCoordinates = height / 6;
if (Velocity == 0)
xVelocity = 2;
else
xVelocity = -2;
if (Velocity == 0)
yVelocity = 2;
else
yVelocity = -2;
}
void movementLimits() {
if (xCoordinates - 10 <= 0 || xCoordinates + 10 >= width)
xVelocity *= -1;
if (yCoordinates + 10 >= height)
yVelocity *= -0.9;
if (yCoordinates - 10 <= 0)
yVelocity *= -1;
}
void movements() {
xCoordinates += xVelocity;
yCoordinates += yVelocity;
yVelocity += gravity;
}
void display() {
background(50);
fill(255);
stroke(255);
circle(xCoordinates, yCoordinates, 20);
}
}
Problem 1:
Both of your objects are shaing the same cooridinates and velocity. They are stored globally so when one object changes it, the change is used by the other object as well. To fix this you should give your Ball class properties to hold the coordinates and velocities.
class Ball{
float x;
float y;
float dx;
float dy
public Ball(float x, float y, float dx, float dy){
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
}
}
Problem 2:
In the display function in Ball, you call background(50);. This will basicly cover the entire screan with the new background; over any previous balls which includes ball1. However, if you remove this line you'll get a kind of cool effect cause by all previous ball drawing sticking around. You should move the background(50); line to the beginning of the draw function. This way, you draw the two balls, draw over them with gray, then redraw the two balls in their new positions.

how to Instantiate prefab with view as a grid in side camera view

i want to create a view like grid with prefabs inside camera view but i'm unable to do so. prefabs are going out of the camera view. can any one help me to resolve this? i want to place prefab as a grid and 9 * 6 grid.
public GameObject tilePrefab;
Vector2 mapSize;
void Start()
{
createGrid();
Debug.Log("Screen Width : " + Screen.width);
Debug.Log("Screen Height : " + Screen.height);
mapSize = new Vector2(Screen.width/9,Screen.height/12);
Debug.Log("mapSize : " + mapSize);
}
void createGrid()
{
for (int x = 0; x < 9; x++)
{
for (int y = 0; y < 6; y++)
{
Vector3 tilePosition = new Vector3(-mapSize.x+0.5f + x,-mapSize.y + 0.5f+y ,0 );
GameObject ballclone = (GameObject)Instantiate(tilePrefab,tilePosition,Quaternion.identity);
ballclone.transform.parent = transform;
}
}
}
You can use ViewportToWorldPoint
for (int x = 0; x < 9; x++)
for (int y = 0; y < 6; y++)
xx.position = camera.ViewportToWorldPoint(new Vector3(1f/9*x, 1f/6*y, distance));
distance is the distance between the camera and the object.