Im working in Unity and I have a simple scene. It consists of a cube which has a box collider on it. Below this cube is a plane
I want to know which side of the cube is hitting the plane at any given instant
One way to do this is to cast a ray from each side of the cube and determine which ray is colliding with the plane
But i fear that it may be performance heavy. Is there a way to do this in an efficient manner?
I used for same need:
1) Place plane for each side of cude;
2) Set clear color for planes;
3) Write script that check plane position (in your option need loop that search plane with lower position.
If you're just looking for a way other than just ray casting then you could create a method that takes in your cube's position and your plane's position and then do some calculations.
Vector3 heading = plane.transform.position - cube.transform.position;
float distance = heading.magnitude;
Vector3 direction = heading / distance;
From here you would just have to check what that direction is.
Related
I'm trying to make a character that walks around a platform and if the character reach a corner, it rotates and continue walking on the side of the platform, same with the bottom part.
This is a visual representation of what I'm trying to achive.
Movement
The specific problem is when the character reach the corners, the rotation just go crazy. I'm trayng to achive this using a raycast from the character to the platform and if the raycast doesn't find floor, I start the rotation like this:
times++;
transform.rotation = Quaternion.Slerp(transform.rotation,Quaternion.AngleAxis(times*-89.9f,Vector3.forward),Time.deltaTime * RotationSpeed);
_characterGravity.SetGravityAngle(transform.localEulerAngles.z);
I'm using a characterGravity script that allows me to change the gravity direction for the character in order to not fall when is walking upside down or on the sides. But this is not working propperly. Is there a better way to do this?
Assuming your 2D view is aligned on the X-Y plane, with the Z-axis aimed into the screen (the same direction the camera is facing), I suggest using Transform.Rotate() instead of trying to linearly interpolate the rotation between two values:
if (ShouldRotateAroundCorner()) {
transform.Rotate(Vector3.forward, RotationSpeed * Time.deltaTime);
}
You'll just need to make sure your ShouldRotateAroundCorner() knows when to start and stop the 90 degree turn, which will take a little bit of additional code to keep track of when it's in this state change.
I have a GameObject.Plane in a given position for visual purposes.
From that, given the plane's rotation and position in world space, I have to make a mathematical plane to use in the next calculations, but something's off.
I've tried doing
new Plane(go.transform.InverseTransformDirection(-go.transform.right), go.transform.InverseTransformPoint(go.transform.position));
where go is the primitive plane object.
Its position in world space seems fine, judging from the later results, but the rotation is not.
The Primitive plane(go) is rotated 90 degrees so instead of facing upwards it's facing the side.
What's going wrong here?
Edit: Current setup is
go.transform.InverseTransformDirection(-go.transform.right);
return new Plane(go.transform.up, go.transform.position);
void OnDrawGizmos()
{
Gizmos.color = Color.magenta;
Gizmos.DrawLine(planePrimitive.transform.position, planePrimitive.transform.position + plane.normal * 3f);
}
This
go.transform.InverseTransformDirection(-go.transform.right)
returns a vector facing to the side and you are using it as the Plane's normal.
A primitive Plane object's normal is simply it's local transform.up vector.
Then note that a Plane takes world space coordinates so it makes no sense to use InverseTransformDirection and InverseTransformPoint since transform.up and transform.position already are in world space.
new Plane(go.transform.up, go.transform.position);
If you are rather talking about a primitive Quad object then the vector you want is -transform.forward instead.
new Plane(-go.transform.forward, go.transform.position);
To your Gizmos:
You are using the testPlane.normal like it was a position. It is not! The normal is a direction and doesn't tell anything about the position.
What you want to do would be e.g. (without using local space gizmos)
Gizmos.DrawLine(go.transform.position, go.transform.position + testPlane.normal * 3f);
or if you can depend only on the plane itself use
Gizmos.DrawLine(plane.distance, plane.distance + testPlane.normal * 3f);
In this second plane the plane.distance is the vector from 0,0,0 to the closest point on the plane. It will therefore still not be exactly in the position of the given plane object.
I'm trying to create a game where a ball is launched off from a circle, much like a cannon, but it can be launched into any direction, 360ยบ because the circle which the ball is attached to can rotate. So, I was thinking of using Rigidbody2D.AddForce() but I'm not sure how to define the direction I want the force to be applied. I want it to be the direction perpendicular to the ball/player's movement but I don't know how to define that. Thanks for any help! :)
If you get the direction that the ball is travelling (as say degrees) you can add a certain angle to that and use the angle to determine the force that needs to be applied.
I'm assuming that the ball/player has no ridged body, if it does then you can just grab the direction directly. Also since your using circle to describe the spawned shape i'm going to assume your working in 2D.
Vector3 lastPosition;
void Update()
{
//launch the ball before updating the last position
lastPosition = transform.position;
}
Vector3 launchDirection()
{
Vector3 ballDirection = transform.position - lastPosition;
float angle = Mathf.Atan2(ballDirection.x, ballDirection.y) * Mathf.Rad2Deg;
//the direction should be perpendicular to direction of movement
float angle += 90;
return new Vector2(Mathf.Cos(angle), Mathf.Sin(angle));
}
I haven't ran the code in unity but it looks like it should work. Basically to get the direction you store the last position and compare it to the current direction to work out the delta (if your using a ridged body to move around then grab the direction from that instead) then use atan2 to get the angle. To make the launch direction perpendicular to the ball I added 90 degrees (you might want -90 depending on what side you need the circle to launch from). Now that we have the angle that you want the ball to shoot out from, use that with Sin and Cos to get the XY of the angle.
There you have it that will get you the direction perpendicular to movement, you your using 3 dimensions it's basically the same maths just with a few numbers thrown in to pad the return value.
Oh if your object always faces the direction of movement transform.right also works :P
I am trying to figure out how to modify HelloARController.cs from the example ARCore scene to place objects directly in front of the camera. My thinking is that we are raycasting from the camera to a Vector3 on an anchor or tracked plane, so can't we get the Vector3 of the start of that ray and place an object at or near that point?
I have tried lots, and although I am somewhat a beginner, I have come up with this
From my understanding, ScreenToWorldPoint should output a vector3 of the screen position corresponding to the world, but it is not working correctly. I have tried other options instead of ScreenToWorldPoint, but nothing has presented the desired effect. Does anyone have any tips?
To place the object right at the middle of the camera's view, you would have to change the target gameObject's transform.position (as AlmightyR has said).
The ready code would look something like this:
GameObject camera;
GameObject object;
float distance = 1;
object.transform.position = camera.transform.position + camera.transform.forward * distance;
Since camera's forward component (Z axis) is always poiting at the direction where Camera is looking to, you take that vector's direction and multiply it by a distance you want your object to be placed on. If you want your object to always stay at that position no matter how camera moves, you can make it a child of camera's transform.
object.transform.SetParent(camera.transform);
object.transform.localPosition = Vector3.forward * distance;
Arman's suggestion works. Also giving credit to AlmightyR since they got me started in the right direction. Here's what I have now:
// Set a position in front of the camera
float distance = 1;
Vector3 cameraPoint = m_firstPersonCamera.transform.position + m_firstPersonCamera.transform.forward * distance;
// Intanstiate an Andy Android object as a child of the anchor; it's transform will now benefit
// from the anchor's tracking.
var andyObject = Instantiate(m_andyAndroidPrefab, cameraPoint, Quaternion.identity,anchor.transform);
The only problem with this is that because of the existing HelloAR example code, an object is only placed if you click on a point in the point cloud in my case (or a point on a plane by default). I would like it to behave so that you click anywhere on screen, and it places an object anchored to a nearby point in the point cloud, not necessarily one that you clicked. Any thoughts for how to do that?
Side tip for those who don't know: If you want to place something anchored to a point in the cloud, instead of on a plane, change
TrackableHitFlag raycastFilter = TrackableHitFlag.PlaneWithinBounds | TrackableHitFlag.PlaneWithinPolygon;
to
TrackableHitFlag raycastFilter = TrackableHitFlag.PointCloud;
curious on how I would make a SKSpriteNode walk smoothly across bumpy terrain (Image below evaluating "Bumpy Terrain")
I also want the image to have an SKPhysicsBody. How can I possibly do this?
Having just done that (in Unity) the basic premise is as follows:
cast a ray downwards from the center of the body to its "feet" (ie ray length is equal to half height of the body/node)
if the ray intersects with a body, check if the body is "walkable" (ie somehow defined as a ground body, for simplicity you can just check if the body is non-dynamic, for more fine-grained control compare the category and contact bitmasks of the intersecting bodies)
if you found an intersecting, walkable body, set the body's position to where the ray hit the other body, plus half the body/node's height
In Sprite Kit the only way to get the intersection point from a raycast is to use enumerateBodiesAlongRayStart:end:usingBlock: of the SKPhysicsWorld class. If your character can only walk up straight (ie he won't rotate to adapt to the terrain, and the terrain doesn't have "loops") you only need to check the Y coordinate of the intersection point.
Say your node's position is at Y=340 and the ray intersects at Y=310 and your node's height is 80 then:
(340 - 310) + 80 / 2 = 70
Then 70 is the distance from the floor your player should be positioned at, to be exact it's the Y coordinate where the ray hit the floor (310) plus this 70 which gives you Y=380 as the new height. Keep the X coord and change the Y coord as you walk over the plane.
Of course the ground plane needs to be a physics body, specifically using an edge shaped body. There are tools that let you design those points from shapes, most prominently PhysicsEditor. But for a start you can experiment with a single line segment, sloped at an angle to test if your character is properly walking the plane up or down.
Note that if you are using physics you should probably set the physics body's velocity to 0,0 after you determined a ground hit, otherwise velocity may accumulate and the body eventually falls through the floor, or can't jump, or do other weird stuff.