Using this tutorial https://www.youtube.com/watch?v=waEsGu--9P8&list=PLzDRvYVwl53uhO8yhqxcyjDImRjO9W722 and Quaternions I've made a function, that finds the World Position of the grid tiles for Isometric Tilemap.
private Vector3 GetWorldPosition(int x, int y, int r, int u, int f) {
return Quaternion.AngleAxis(u, Vector3.up) * Quaternion.AngleAxis(r, Vector3.right)
* Quaternion.AngleAxis(f, Vector3.forward) * new Vector3(x, y) * cellSize;
}
It works perfectly well. It rotates a 2D grid to fit Unity isometric Tilemap. Now i need to do the opposite - get the tile, if i know the worldPosition. I supposed, if in the previous case I multiplied the Quaternions, now i need to divide the worldPosition.x and worldPosition.y by them. But this code
private void GetXY(Vector3 worldPosition, out int x, out int y, int r = 60, int u = 0, int f = 45) {
Quaternion rotation = Quaternion.AngleAxis(u, Vector3.up) * Quaternion.AngleAxis(r, Vector3.right)
* Quaternion.AngleAxis(f, Vector3.forward);
x = Mathf.FloorToInt(worldPosition.x / rotation / cellSize);
y = Mathf.FloorToInt(worldPosition.y / rotation / cellSize); }
does not even run, because of the mistake
"Operator '/' cannot be applied to operands of type 'Quaternion' and
'float'"
So why could I multiply Quaternion and float cellSize in the first case, but can not divide or multiply them in the second case?
And how to do the opposite operation?
Thank you for trying to help, but Inverse did not work out.
So I had 2D grid, that was rotated -45 degrees Z and 60 degrees X. It made the grid isometric. So because it was rotated X by 60 degr., in 2D vision this grid had more than 90 degrees between its own X and Y (the tiles were rhombus). And i found out the exact angles, which i can use for the coordinates - different for x and y. This function got the tiles right for me.
private Vector2Int GetXY(Vector3 worldPosition) {
Vector3 positionX = Quaternion.AngleAxis(-65, Vector3.forward) * worldPosition / cellSize;
Vector3 positionY = Quaternion.AngleAxis(-26, Vector3.forward) * worldPosition / cellSize;
return new Vector2Int(Mathf.FloorToInt(positionX.x * 1.55f), Mathf.FloorToInt(positionY.y * 1.55f));
}
Related
A little bit confused - math is really not my strong point, so I'm not sure how to achieve.
Currently the objects instantiate, but I have no control over the distance from center or the rotation of each spawned object
public void instantiateInCircle()
{
for (int i = 0; i < amount; i++)
{
float radius = spawnDistance;
float angle = i * Mathf.PI * 2f / radius;
Vector3 newPos = transform.position + (new Vector3(Mathf.Cos(angle) * radius, spawnHeight, Mathf.Sin(angle) * radius ));
//Rotate objects to look at the center
GameObject instantiatedObject = Instantiate(itemToSpawn, newPos, Quaternion.Euler(0, 0, 0));
instantiatedObject.transform.LookAt(spawnAroundThis.transform);
//How to adjust the width of the radius, how far away from the center?
//Parent instantiated objects to disk
instantiatedObject.transform.parent = spawnAroundThis.transform;
instantiatedObject.transform.localScale = new Vector3(scale, scale, scale);
}
}
How to make the distance adjustable, move cubes in closer to center...?
Currently, you do not access the instantiated object, but the prefab instead. Cache the object and call the LookAt on them.
Since I do not know what type itemToSpawn is, I assumed it is a GameObject. You may want to use your type instead.
GameObject instantiatedObject = Instantiate(itemToSpawn, newPos, Quaternion.Euler(0, 0, 0));
instantiatedObject.transform.LookAt(spawnAroundThis.transform);
If you want to control the distance from center of the rotation:
for (int i = 0; i < amount; i++)
{
float radius = spawnDistance;
float angle = i * Mathf.PI * 2f / (float)amount; // divide by amount, NOT radius
// manipulate radius here as you want
Vector3 newPos = transform.position + (new Vector3(Mathf.Cos(angle) * radius, spawnHeight, Mathf.Sin(angle) * radius ));
...
}
I'm writing a class to help with mouse movement and I can't seem to get the move with distance and angle function to work properly, it always seems to move the mouse in a 45 degree angle.
public static POINT moveDistanceAngle(POINT start, double distance, double angle)
{
double radians = angleToRadians(angle);
int x = (int)Math.Round(Math.Cos(radians) * distance);
int y = (int)Math.Round(Math.Sin(radians) * distance);
return new POINT(start.X + x, start.Y + y);
}
I'm using GetCursorPos to get the point.
public static double angleToRadians(double angle)
{
return (Math.PI / 180) * angle;
}
Have I done something wrong with the maths?
Apologies for this dumb post. After spending hours on it I figured out the actual issue was in my maths to set the mouse cursor and not in the maths. This post actually has the right maths.
It looks like angle has measured in radians not degrees and you make double conversion to radians::
public static POINT moveDistanceAngle(POINT start, double distance, double angleRad)
{
int x = (int)Math.Round(Math.Cos(angleRad) * distance);
int y = (int)Math.Round(Math.Sin(angleRad) * distance);
return new POINT(start.X + x, start.Y + y);
}
I have a staggered (zigzag) dimetric tile layout. The tiles are 128x64, so not truly isometric.
float offsetX = 0f;
if(gridX % 2 != 0)
offsetX = tileSize.x / 2f;
float worldX = gridY * tileSize.x + offsetX;
float worldY = gridX * tileSize.y / 2f;
How do I flip/rotate the layout, so that it looks like this:
I tried swapping out x and y coordinates, but it was always breaking my layout, so I must be missing something.
(x, y) rotated by 90 degrees clockwise is (y, -x). (y, x) is merely a reflection about the line y = x
I've been trying to reduce the code used in my voxel / planar terrain generator, and wrote this function in order to call every time I need to add a new set of UV's - representing four vertex in a texture map:
List<Vector2> _UVs(List<Vector2> UV, int x = 0, int y = 0)
{
List<Vector2> UVReturn = new List<Vector2>();
UVReturn = UV;
UVReturn.Add(new Vector2 (0f, 0f) * x);
UVReturn.Add(new Vector2 (0.125f, 0) * y);
UVReturn.Add(new Vector2 (0.125f, 1)* y);
UVReturn.Add(new Vector2 (0f, 1f) * x);
return UVReturn;
}
However, I can't seem to identify the exact spots to write in the modifiers, they seem to throw things off every time. I currently have a single row of 128x textures in a 1024 file. The UV layout for the moment seems exact, except for the multiplication. Remove that and it shows the first texture, perfectly. What ways can this be improved on? My goal would be to get it to where it could be used for any four vertex plane.
You can't just multiply it like that, that's something completely different.
UVReturn.Add(new Vector2 (x * 0.125f, 0f));
UVReturn.Add(new Vector2 ((x + 1) * 0.125f, 0));
UVReturn.Add(new Vector2 ((x + 1) * 0.125f, 1));
UVReturn.Add(new Vector2 (x * 0.125f, 1f));
You need to offset the UV coordinates - that means you have to add x * widthOfOne to the x coordinates, and y * heightOfOne to the y coordinates. My sample only shows the x-offset, but you can easily expand it to allow y-offsets as well.
I just need to rotate a model 90 degrees when it starts, without editing its local axis.
I have a missile flying 90 degrees sideways down a tunnel, and I need it to be facing down the tunnel while still retaining its movement directions. I've tried:
virtual public void setOrientationWorld(float x, float y, float z)
{
mOrientation *= Matrix.CreateRotationX(MathHelper.ToRadians(x));
mOrientation *= Matrix.CreateRotationY(MathHelper.ToRadians(y));
mOrientation *= Matrix.CreateRotationZ(MathHelper.ToRadians(z));
}
setOrientationWorld(0, -90, 0);
And I've tried:
virtual public void setOrientationLocal(float x, float y, float z)
{
mOrientation *= Matrix.CreateFromAxisAngle(mOrientation.Right, MathHelper.ToRadians(x));
mOrientation *= Matrix.CreateFromAxisAngle(mOrientation.Up, MathHelper.ToRadians(y));
mOrientation *= Matrix.CreateFromAxisAngle(mOrientation.Forward, MathHelper.ToRadians(z));
}
setOrientationLocal(0, -90, 0);
But they both ruin everything. When I do either, the missile rotates, and all the axis's change. Even just going setPosition(0,0,-1) makes it move along the worlds X axis instead of it's Z.
I have tried moving the missile both locally and globally, but to no avail, like this:
virtual public void moveLocal(float x, float y, float z)
{
mPosition += mOrientation.Right * x;
mPosition += mOrientation.Up * y;
mPosition += mOrientation.Forward * z;
}
And
virtual public void moveWorld(float x, float y, float z)
{
mPosition.X += x;
mPosition.Y += y;
mPosition.Z += z;
}
The only other relevant thing I can think of is the draw function, which may have something to do with it:
foreach (BasicEffect effect in mesh.Effects)
{
effect.EnableDefaultLighting();
effect.World = Matrix.Identity *
Matrix.CreateScale(mScale) *
transforms[mesh.ParentBone.Index] *
Matrix.CreateTranslation(mPosition) *
mOrientation;
effect.View = game1.getView();
effect.Projection = game1.getProjection();
}
Pls Halp!
The order you apply the translation and rotation is important. If you are applying the rotation globally then translating first will cause problems as you are moving the object away from it's centre of rotation. In that case you need to rotate and then translate.
When applying the rotations in the local space of the missile, the order you apply the rotations is important too. Applying them in the order "Roll", "Pitch", "Yaw" will produce a different result to applying them in the order "Pitch", "Yaw", "Roll" and so on for all six combinations. The order is dependent on what you are trying to achieve so you may have to create a method that can do all six and selects which one based on a parameter.