Detecting overlapping polygon2D colliders in Unity - c#

I'm trying to program an isometric building placement script. Each building has a PolygonCollider2D component on it with a trigger. When placing a new building, I'm trying to check if the PolygonCollider2D of the placed building overlaps with anything else (to check if placement is valid). My code is as follows:
Adjust the points of the new placed building collider based on the mouse position
Vector2[] points = polygonCollider2D.points;
points.SetValue(polygonCollider2D.points[0] + (Vector2)mousePosition, 0);
points.SetValue(polygonCollider2D.points[1] + (Vector2)mousePosition, 1);
points.SetValue(polygonCollider2D.points[2] + (Vector2)mousePosition, 2);
points.SetValue(polygonCollider2D.points[3] + (Vector2)mousePosition, 3);
polygonCollider2D.points = points;
Set up contact filter:
ContactFilter2D contactFilter2D = new ContactFilter2D();
contactFilter2D.useTriggers = true;
contactFilter2D.SetLayerMask(polygonCollider2D.gameObject.layer);
Check for collisions
List<Collider2D> list = new List<Collider2D>();
Debug.Log(polygonCollider2D.OverlapCollider(contactFilter2D, list));
However if there is already a building there, it still does not register an overlap.
What am I missing / doing wrong ?
Thanks so much for the help!

Your code which sets the polygon collider points seems to be the issue here. If that code runs multiple times, it will repeatedly offset the collider further and further away from its original position. You probably don't want to be changing the actual collider; usually you should move object which has the collider. So you would replace those lines with something like this:
gameObject.transform.position = mousePosition;

Related

Unity: How can I put one object on top of another

I need put my 3D Object dynamicly to platform because 3D Object has a different size.
My code is _sceneObject.sceneItem.transform.localPosition = _gobletPlatform.localPosition; but he fixes on it, not on top of it.
Collider platformCollider = (_gobletPlatform.GetComponent<Collider>();
Vector3 pos = new Vector3 (_gobletPlatform.transform.position.x + platformCollider.bounds.size.x, _gobletPlatform.transform.position.y + platformCollider.bounds.size.y, _gobletPlatform.transform.position.z + platformCollider.bounds.size.z);
_sceneObject.sceneItem.transform.position = pos;
Note: I can't test this now. But, I hope it works.

Moving and scaling an object according to hand position

I need some help with my college project. I have a cylinder and need it to act as a coil. For example, if I touched the cylinder's surface it's height will decrease (scaled in the y direction) as if pressing on a coil then when I remove my hand it returns back to its original size.
This is what I reached till now but I still have some problems that I can't solve.
public class Deformation : MonoBehaviour
{
Vector3 tempPos;
private void InteractionManager_SourceUpdated(InteractionSourceUpdatedEventArgs hand)
{
if (hand.state.source.kind == InteractionSourceKind.Hand)
{
Vector3 handPosition;
hand.state.sourcePose.TryGetPosition(out handPosition);
float negXRange = transform.position.x - transform.localScale.x;
float posXRange = transform.position.x + transform.localScale.x;
float negYRange = transform.position.y - (transform.localScale.y / 2);
float posYRange = transform.position.y + (transform.localScale.y / 2);
float negZRange = transform.position.z - transform.localScale.z;
float posZRange = transform.position.z + transform.localScale.z;
float handX = handPosition.x;
float handY = handPosition.y;
float handZ = handPosition.z;
if ((negXRange <= handX) && (handX <= posXRange) && (negYRange <= handY) && (handY <= posYRange) && (negZRange <= handZ) && (handZ <= posZRange))
{
tempPos.y = handPosition.y;
transform.localScale = tempPos;
}
else
{
tempPos.y = 0.3f;
transform.localScale = tempPos;
}
}
}
// Use this for initialization
void Start()
{
tempPos = transform.localScale;
InteractionManager.InteractionSourceUpdated += InteractionManager_SourceUpdated;
}
I attached two scripts to my object (cylinder) the TapToPlace script from the HoloToolKit and the deformation script stated above. The problem is when I deploy to my HoloLens to test, when I place the cylinder first to the needed place then try to deform it after that, it is placed but not deformed. If I tried it the other way around both work. Any ideas why does the deformation script does not work after the TapToPlace one?
The cylinder when viewed by my HoloLens is somehow transparent. I mean that I can see my hand through it. I need it to be more solid.
I wonder if there is something like a delay that I can use because when I use the deformation script stated above the cylinder is scaled to my hand position then scaled back to its default size very fast and appears as if blinking.
At first I place the cylinder on a setup (something as a table for example) then I begin to deform it. When I commented the else part in the deformation script stated above, it was scaled and left stable without returning to the original size. It is scaled symmetrically so its height is decreased from up and down resulting in the base of the cylinder becomes away from the table. I need the base of the cylinder to be always stable and touching the table under it.
Note: I am using Unity 2017.3.1f1 (64-bit) - HoloToolkit-Unity-2017.2.1.3
Thank you in advance.
1) Did you see the MRTK 2017.2.1.4 release? It has some useful features such as two handed resizing/scaling of objects. The BoundingBox code in the new MRTK release does moving and resizing in one component, it might be a better base to start from than the TapToPlace, or at least show how the two types of transform can work together.
2) What colour is your object? Hololens will render black as transparent, so try making the object bright white for testing. Also, just double check the brightness is turned up to full (the LHS buttons on the hololens). Finally, check your shader is the MRTK Standard shader. (again, the 2017.2.1.4 release has new shader code you might want to try.) . In a room without direct sunlight it should pretty much cover up your hand.
4) I'm not sure I follow completely, but the pivot point could be important here. If it is centred in the middle of the coil (as I'd imagine it is) then when you deform the coil down it will still stay centered at that central pivot point.
If you instead set the pivot point to the bottom of the coil, touching the table, you can scale and that point stays on the table and the top does all the moving.

Disable/Toggle visualization of tracked planes in ARCore unity

I have been looking on the code for ARCore Unity for a while and I want to do one simple task that is, to have a toggle button so user can place an object in the scene while knowing where to place it while the tracked planes are visible and once the user places the object, he is given the option of just visually disabling the tracked planes so it looks more realistic. I was able to do this in Android Studio by doing something like this in the main HelloArActivity.java:
if (planeToggle) {
mPlaneRenderer.drawPlanes(mSession.getAllPlanes(), frame.getPose(), projmtx);
}
this was really simple. I made a bool named planeToggle and just placed the mPlaneRenderer.drawPlanes function in an if condition. When the bool is true it displays the planes and when its false, it does not...
However, with Unity I am confused. I did something like this in the HelloARController.cs :
I made a button to togglePlanes.
Set an event listener to it to toggle a boolean variable and did something like this :
for (int i = 0; i < m_newPlanes.Count; i++)
{
// Instantiate a plane visualization prefab and set it to track the new plane. The transform is set to
// the origin with an identity rotation since the mesh for our prefab is updated in Unity World
// coordinates.
GameObject planeObject = Instantiate(m_trackedPlanePrefab, Vector3.zero, Quaternion.identity,
transform);
planeObject.GetComponent<TrackedPlaneVisualizer>().SetTrackedPlane(m_newPlanes[i]);
m_planeColors[0].a = 0;
// Apply a random color and grid rotation.
planeObject.GetComponent<Renderer>().material.SetColor("_GridColor", m_planeColors[0]);
planeObject.GetComponent<Renderer>().material.SetFloat("_UvRotation", Random.Range(0.0f, 360.0f));
if (togglePlanes == false){ // my code
planeObject.SetActive(false); // my code
} //
}
Nothing happens when I press the toggle button.
The other option I had was to make changes in the TrackedPlaneVisualizer.cs where I did something like this :
for (int i = 0; i < planePolygonCount; ++i)
{
Vector3 v = m_meshVertices[i];
// Vector from plane center to current point
Vector3 d = v - planeCenter;
float scale = 1.0f - Mathf.Min((FEATHER_LENGTH / d.magnitude), FEATHER_SCALE);
m_meshVertices.Add(scale * d + planeCenter);
if (togglePlanesbool == true) // my code
{
m_meshColors.Add(new Color(0.0f, 0.0f, 0.0f, 1.0f)); // my code
}
else
{
m_meshColors.Add(new Color(0.0f, 0.0f, 0.0f, 0.0f)); // my code
}
}
This did work. But I am experiencing delays in toggling and sometimes if two different planes have been rendered they start toggling between themselves(if one is enabled, other gets disabled). So I guess this is also not the option to go for....Anyone who can help?
Note that I am a beginner in Unity.
The sample isn't really designed to hide and show the planes, so you have to add a couple things.
First, there is no collection of the GameObjects that represent the ARCore planes. The easiest way to do this is to add a tag to the game objects:
In the Unity editor, find the TrackedPlaneVisualizer prefab and select it. Then in the property inspector, drop down the Tag dropdown and add a tag named plane.
Next, in the Toggle handler method, you need to find all the game objects with the "plane" tag. Then get both the Renderer and TrackedPlaneVisualizer components and enable or disable them based on the toggle. You need to do both components; the Renderer draws the plane, and the TrackedPlaneVisualizer re-enables the Renderer (ideally it would honor the Renderer's state).
public void OnTogglePlanes(bool flag) {
showPlanes = flag;
foreach (GameObject plane in GameObject.FindGameObjectsWithTag ("plane")) {
Renderer r = plane.GetComponent<Renderer> ();
TrackedPlaneVisualizer t = plane.GetComponent<TrackedPlaneVisualizer>();
r.enabled = flag;
t.enabled = flag;
}
}
You can also do a similar thing where the GameObject is instantiated, so new planes honor the toggle.

Sliding with collision using OBB

In my C# 3D game:
I have a OBB (orientated bounding box) for my wall. My player is another tiny obb. I have good collision detection use SAT (separating axis theorem). When the collision occurs I have the old position of the player (where no collision occurred) and the position change the player experienced. To calculate the new position I use: Position = OldPosition + PositionChange; I also have a function which detects when I am colliding with any Wall in my world, It will return null if there is no collision and it will return an Wall if there is a collision. A Wall is a class I have added which has a model, OBB, and position. If (IntersectsAnyWall() == null) //no collision
That works well however I don't have sliding working. By sliding I mean when the player walks into a wall at an angle he slides along it instead of just stopping. Splitting the movement up into X and Z components and then testing both of them separately creates a jittering effect which is not what I want.
Can anyone give me a suggestion on how to approach sliding with OBB collision?
The wall can be modelled to stop only movements in the wall's normal's direction. In order to allow sliding, you have to find the wall's normal at the collision site. Furthermore, it would be a good idea to calculate, how deep the collision has taken place. Then all you have to do is subtract the "unpassable" part:
Position = OldPosition + PositionChange
if(IntersectsAnyWall() != null)
{
var normal = //wall's normal at collision site
var collisionDepth = ...;
Position += collisionDepth * normal;
}
If you can't calculate the collision depth, you may also subtract the entire part along the normal:
Position = OldPosition + PositionChange
if(IntersectsAnyWall() != null)
{
var normal = //wall's normal at collision site
var partAlongNormal = Vector2.Dot(PositionChange, -normal);
Position += partAlongNormal * normal;
}

Applying force to a dynamically created object

I have a problem with trying to apply force to an object after it has been dynamically created.
Let me start by mentioning that I havn't been working in silverlight and with c# for very long and my code is not likely to be very efficient in what it does, but I am trying to make it work.
I have a spaceship that will fire a bullet on keypress. I create this bullet and have it appear a few pixels above the spaceship. Now I want to have it travel across the screen and I just can't get it to work.
private void fireShot()
{
double playerY = 0;
double playerX = 0;
PhysicsSprite player = _physicsController.PhysicsObjects["Player"];
playerX = player.Position.X;
playerY = player.Position.Y;
ucStaticPlanet shot = new ucStaticPlanet();
shot.Name = "shot_" + shotcount;
shotcount++;
shot.SetValue(Canvas.LeftProperty, Convert.ToDouble(playerX));
shot.SetValue(Canvas.TopProperty, Convert.ToDouble(playerY - 50));
LayoutRoot.Children.Add(shot);//adds the planet to the canvas
_physicsController.AddPhysicsBodyForCanvasWithBehaviors(shot.LayoutRoot);
The bullet that is created does not move upon creation. It is instead just going to get dragged towards to the ground due to the gravity I have in place. I want the bullet to have some speed as it is created, so as to act like a bullet.
I appreciate any help I can get.

Categories