I have 2 objects. It will be in various direction and distance.
How can i instantiate objects between them with a specific distance.
var centerLocation : Vector3 = Vector3.Lerp(object2.transform.position - object1.transform.position, 0.5);
Vector3.Lerp will determine the Vector3 location between 2 Vector3s at a specified percentage. 0.5 = 50%.
My suggestion would be to calculate the vector between the two objects, like this
Vector3 objectLine = (object2.transform.position - object1.transform.position);
Store the magnitude of that vector
float distance = objectLine.magnitude;
Then, normalise the vector;
objectLine = objectLine.normalized;
Iterate through the line, instanciating the object you want to create a specific distances
Vector3 creationPoint = object1.transform.position;
float creationPointDistance = (object1.transform.position -
object1.transform.position);
while(creationPointDistance < distance)
{
creationPoint += objectLine * NEW_OBJECT_DISTANCE;
creationPointDistance = (object1.transform.position -
object1.transform.position);
if(creationPointDistance < distance)
{
objects.Add((GameObject)Instanciate(newObject, creationPoint,
new Vector3(0.0f,0.0f,0.0f)));
}
}
What that will do is set the initial point to be object1's position. It will then move a set distance along the vector between object 1 and object 2, check it's within the two objects, and if it is, instanciate the object, storing it in a list of gameobjects.
That hopefully should do it. I don't have Unity (or any IDE) in front of me to check the syntax.
Related
I am trying to have a gameobject in unity react with sound if another object is inside it. I want the gameobject to use the entering objects location to then see what voxel is closest and then play audio based on the voxel intensity/colour. Does anyone have any ideas? I am working with a dataset that is 512x256x512 voxels. I want it to work if the object is resized as well. Any help is much appreciated :).
The dataset I'm working with is a 3d .mhd medical scan of a body. Here is how the texture is added to the renderer on start:
for (int k = 0; k < NumberOfFrames; k++) {
string fname_ = "T" + k.ToString("D2");
Color[] colors = LoadData(Path.Combine (imageDir, fname_+".raw"));
_volumeBuffer.Add (new Texture3D (dim [0], dim [1], dim [2], TextureFormat.RGBAHalf, mipmap));
_volumeBuffer[k].SetPixels(colors);
_volumeBuffer [k].Apply ();
}
GetComponent<Renderer>().material.SetTexture("_Data", _volumeBuffer[0]);
The size of the object is defined by using the mdh header files spacing as well as voxel dimensions:
transform.localScale = new Vector3(mhdheader.spacing[0] * volScale, mhdheader.spacing[1] * volScale * dim[1] / dim[0], mhdheader.spacing[2] * volScale * dim[2] / dim[0]);
I have tried making my own function to get the index from the world by offsetting it to the beginning of the render mesh (not sure if this is right). Then, scaling it by the local scale. Then, multiplying by the amount of voxels in each dimension. However, I am not sure if my logic is right whatsoever... Here is the code I tried:
public Vector3Int GetIndexFromWorld(Vector3 worldPos)
{
Vector3 startOfTex = gameObject.GetComponent<Renderer>().bounds.min;
Vector3 localPos = transform.InverseTransformPoint(worldPos);
Vector3 localScale = gameObject.transform.localScale;
Vector3 OffsetPos = localPos - startOfTex;
Vector3 VoxelPosFloat = new Vector3(OffsetPos[0] / localScale[0], OffsetPos[1] / localScale[1], OffsetPos[2] / localScale[2]);
VoxelPosFloat = Vector3.Scale(VoxelPosFloat, new Vector3(voxelDims[0], voxelDims[1], voxelDims[2]));
Vector3Int voxelPos = Vector3Int.FloorToInt(VoxelPosFloat);
return voxelPos;
}
You can try setting up a large amount of box colliders and the OnTriggerEnter() function running on each. But a much better solution is to sort your array of voxels and then use simple math to clamp the moving objects position vector to ints and do some maths to map the vector to an index in the array. For example the vector (0,0,0) could map to voxels[0]. Then just fetch that voxels properties as you like. For a voxel application this would be a much needed faster calculation than colliders.
I figured it out I think. If anyone sees any flaw in my coding, please let me know :).
public Vector3Int GetIndexFromWorld(Vector3 worldPos)
{
Vector3 deltaBounds = rend.bounds.max - rend.bounds.min;
Vector3 OffsetPos = worldPos - rend.bounds.min;
Vector3 normPos = new Vector3(OffsetPos[0] / deltaBounds[0], OffsetPos[1] / deltaBounds[1], OffsetPos[2] / deltaBounds[2]);
Vector3 voxelPositions = new Vector3(normPos[0] * voxelDims[0], normPos[1] * voxelDims[1], normPos[2] * voxelDims[2]);
Vector3Int voxelPos = Vector3Int.FloorToInt(voxelPositions);
return voxelPos;
}
Suppose I have an object A at position x = 0 and object B at position x = 16.
Suppose A have this code:
public class Move : MonoBehaviour
{
float speed = 0.04f;
Update()
{
transform.Translate(speed, 0, 0);
}
}
My question is: how to evaluate how many seconds (precisely) will it take for A to collide with B?
If I apply the formula S = S0 + vt, it won't work correctly, because I don't know how to measure how many frames it will pass in a second to exactly measure what speed is.
First of all you shouldn't do that. Your code is currently framerate-dependent so the object moves faster if you have a higher framerate!
Rather use Time.deltaTime
This property provides the time between the current and previous frame.
to convert your speed from Unity Units / frame into Unity Units / second
transform.Translate(speed * Time.deltaTime, 0, 0);
this means the object now moves with 0.04 Unity Units / second (framerate-independent).
Then I would say the required time in seconds is simply
var distance = Mathf.Abs(transform.position.x - objectB.transform.position.x);
var timeInSeconds = distance / speed;
Though .. this obviously still assumes by "collide" you mean at the same position (at least on the X axis) .. you could also take their widths into account since their surfaces will collide earlier than this ;)
var distance = Mathf.Abs(transform.position.x - objectB.transform.position.x) - (objectAWidth + objectBWidth);
var timeInSeconds = distance / speed;
I have two gameObjects A and B. They are rotated at 90 degrees, which makes its local y axis face forward.
1st Case
In this case, the local y position of B is ahead of local y position of A
2nd Case
Even though their global position is same as the 1st case, we can observe here that local y position of A is ahead of local y position of B.
I tried using A.transform.localPosition.y and B.transform.localPosition.y to find which is greater but it doesnt work. What can I do to find which is front in these two different cases?
Vector projections are your friend here. Project both positions onto a line and compare their magnitude (or square magnitude, it's faster).
Case 1:
Vector3 a = Vector3.Project(A.position, Vector3.up);
Vector3 b = Vector3.Project(B.position, Vector3.up);
if (a.sqrMagnitude > b.sqrMagnitude)
{
// a is ahead
}
else
{
// b is ahead
}
Case 2: Project both positions onto Vector3.left.
Maybe you can even always simply project the two positions onto one of the two objects' forward vector (A.forward or B.forward assuming they're rotated equally).
Hope this helps.
You could compare Vector3.Dot(A.position, A.forward) and Vector3.Dot(B.position, B.forward) to find the one in front in relation to their forward.
The object with the bigger Dot product is in front, and this works in all rotations, including 3D ones.
You can use the following snippet to test for yourself:
// Assign these values on the Inspector
public Transform a, b;
public float RotationZ;
void Update() {
a.eulerAngles = new Vector3(0, 0, RotationZ);
b.eulerAngles = new Vector3(0, 0, RotationZ);
Debug.DrawRay(a.position, a.right, Color.green);
Debug.DrawRay(b.position, b.right, Color.red);
var DotA = Vector2.Dot(a.position, a.right);
var DotB = Vector2.Dot(b.position, b.right);
if (DotA > DotB) { Debug.Log("A is in front"); }
else { Debug.Log("B is in front"); }
}
As per my game requirements, I was giving manual force when two cars collide with each other and move back.
So I want the correct code that can justify this. Here is the example, collision response that I want to get:
As per my understanding, I have written this code:
Vector3 reboundDirection = Vector3.Normalize(transform.position - other.transform.position);
reboundDirection.y = 0f;
int i = 0;
while (i < 3)
{
myRigidbody.AddForce(reboundDirection * 100f, ForceMode.Force);
appliedSpeed = speed * 0.5f;
yield return new WaitForFixedUpdate();
i++;
}
I am moving, my cars using this code:
//Move the player forward
appliedSpeed += Time.deltaTime * 7f;
appliedSpeed = Mathf.Min(appliedSpeed, speed);
myRigidbody.velocity = transform.forward * appliedSpeed;
Still, as per my observation, I was not getting, collision response in the proper direction. What is the correct way for getting above image reference collision response?
Until you clarify why you have use manual forces or how you handle forces generated by Unity Engine i would like to stress one problem in your approach. You calculate direction based on positions but positions are the center of your cars. Therefore, you are not getting a correct direction as you can see from the image below:
You calculate the direction between two pivot or center points therefore, your force is a bit tilted in left image. Instead of this you can use ContactPoint and then calculate the direction.
As more detailed information so that OP can understand what i said! In the above image you can see the region with blue rectangle. You will get all the contact points for the corresponding region using Collision.contacts
then calculate the center point or centroid like this
Vector3 centroid = new Vector3(0, 0, 0);
foreach (ContactPoint contact in col.contacts)
{
centroid += contact.point;
}
centroid = centroid / col.contacts.Length;
This is the center of the rectangle to find the direction you need to find its projection on your car like this:
Vector3 projection = gameObject.transform.position;
projection.x = centroid.x;
gameObject.GetComponent<Rigidbody>().AddForce((projection - centroid )*100, ForceMode.Impulse);
Since i do not know your set up i just got y and z values from car's position but x value from centroid therefore you get a straight blue line not an arrow tilted to left like in first image even in the case two of second image. I hope i am being clear.
I'm using a script that i found online that uses a kdTree to calculate the nearest point to an object on the surface of a mesh.
I have the following code in the OnDrawGizmos method that allows me to draw a circle that will orbit the surface of the object.
x = target.transform.position.x + ((Mathf.Cos(tValue)) * (radius));
z = target.transform.position.z + ((Mathf.Sin(tValue)) * (radius));
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(new Vector3(x, y, z), 0.06f);
On the the object i am orbiting the "tValue" ranges from 0 to 6.3 to do a full orbit. My problem is that i am trying to calculate the tValue in the range 0-6.3 of an object that is near the central object. I have used my kdTree system to calculate the vector3 position on the surface of the object and it lines up perfectly.
I calculate the radius used in both the above and below equation with:
Vector3 RadiusDirection = (Vector3.ProjectOnPlane(orbitingSurfaceMeshPos, planet.transform.up) - Vector3.ProjectOnPlane(planet.transform.position, planet.transform.up));
float radius = RadiusDirection.magnitude;
However, when i try to calculate the t-value, i get a completely different value. I figured i could just "reverse" the "equation" and so i've been doing:
float temp = orbiting.z - planet.transform.position.z;
temp = temp / radius;
calculatedTvalue = (Mathf.Asin(temp));
What could i be doing wrong? I have tested my "reversing equation" in an empty scene and new script and it worked fine, if i just took the result of the orbit position calculation and directly reversed it. However, it doesn't work in my game.