Detect collision inside editor - unity3d

I am creating an editor extension to easily create 2D and 3D levels. I can move a generator box using arrow keys and place a prefab assigned on the num keys.
The problem is I want to check that, if the prefab is already at that position, then it will either not allow another prefab to spawn there or delete the new prefab.
Any help would be appreciated.

I can think about two possible solutions, here.
The first one is by using Physics.OverlapSphere. I report the example from the Documentation:
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour {
void ExplosionDamage(Vector3 center, float radius) {
Collider[] hitColliders = Physics.OverlapSphere(center, radius);
int i = 0;
while (i < hitColliders.Length) {
hitColliders[i].SendMessage("AddDamage");
i++;
}
}
}
Basically, with this method, you check for the number of colliders that occupy the given area (the area itself is determined by a centre and a radius).
Another, more "basic" solution would be keeping a data structure (like a Map) containing the spawns' informations (like the coordinates of the already instantiated prefabs): this way, you can check directly from the Map if a prefab has been already instantiated here.
Hope this helps!

Related

Weird results with Transform.TransformDirection()

I'm using portal.TransformDirection() to simulate how the object the code is attached to would rotate if it were a child of the portal object without actually being its child.
This is the code and it works kind of but not really. Only if I rotate the portal Object around the Y axis. It still does something when I rotate around the other axes but not what I'm expecting.
I didn't find anyone else who had this problem so I thought I might ask.
I have a short video that demonstrates how it rotates (https://youtu.be/dfvr4IrA2SU) and here is the code on the object that should rotate with the portal object:
using UnityEngine;
[ExecuteInEditMode]
public class PortalArrow : MonoBehaviour
{
[SerializeField] Transform portal;
[SerializeField] Vector3 eulerRotation;
void LateUpdate()
{
transform.position = portal.position;
transform.eulerAngles = portal.TransformDirection(eulerRotation);
}
}
The variable eulerRotation is just a constant Vector3. nothing special about it.
eulerAngles are no direction and it makes no sense to treat them like one.
The fact that it is also stored as a Vector3 is a pure convinience.
would rotate if it were a child of the portal object without actually being its child.
It sounds like you rather simply want
transform.rotation = portal.rotation;

Lock dimension scale of child meshes in Unity

I am building a mobile app in Unity that allows the user to scale objects in all three dimensions (currently using LeanTouch). This all works fine, but obviously when you scale the parent gameobject everything scales in that dimension. I would prefer to only allow certain meshes contained within the gameobject to actually scale, based on the dimension that is scaling.
For instance, if I have a table, and the user wants to increase the width of the object on the fly (i.e. scale in the X direction), I want the top of the unit to scale, but the thickness of the individual legs remains the same. Right now if you scale the width, the legs themselves increase in thickness.
This image illustrates the issue. As the table is scaled wider, so too are the legs. I would like for the leg B width to stay the same as Leg A, despite the table top "stretching" in the X direction.
These models are made with separate meshes for each component, so I'm not trying to do this to a single mesh.
Is there a way to indicate (or within scripts) that a mesh or gameobject can only scale in two dimensions (for instance the table legs can scale in Y and Z, but not X)? I believe this is called "Plane Locking" in Blender.
Right now I'm using Blender to import a DXF, which I'm converting to .obj or .fbx, however I'm a complete noob at it.
Thanks for any suggestions
I suggest you writing a simple script that anchors one object to another in a specific position, like this:
using UnityEngine;
using UnityEditor;
[ExecuteInEditMode, DisallowMultipleComponent]
public class Anchor : MonoBehaviour
{
public Transform target;
public Vector3 localPosition;
void Update()
{
if (target == null) return;
transform.position = target.position - transform.TransformVector(localPosition);
}
void OnDrawGizmos()
{
if (!enabled) return;
var pos = transform.TransformPoint(localPosition);
Gizmos.color = Color.red;
Gizmos.DrawSphere(pos, HandleUtility.GetHandleSize(pos) * .05f);
}
}
I also suggest you to do an object hierarchy similar to this:
It is advisable that the stretchable object and the anchored object to be siblings with a common parent.
With this, you can transform the table top as much as you want the the legs will remain attached to the position of the anchored objects (that should be childs of the strechable object). If you want a transformation to be applied to both the objects (scaling in the z direction, for example), just transform a common parent. The example is in 2D but it works for 3D too.
Two easy approaches to this problem are : unparent your gameobjects before you scale the parent (move them to a temporary parent, scale the parent and move tham back). Alternatively you can apply an inverse scale to all the children. The two are roughly equivalent. Have in mind in no case the side 'legs' of your combined object will stick to the sides, in 2D you could use RectTransform class for that, but in 3D I think you'll need some extra steps to achieve that.

Instantiating a GameObject which has scripts applied

Fairly new to Unity, but quickly learning.
I have a spawner which is an empty GameObject which spawns balloons. The balloon object which spawns has a movement script applied which follows waypoints.
The issue I am having is that I can't click and drag the waypoints (also empty game objects) onto the public variables, I can only do this if the balloons have been added into the game Hierarchy first, but I'm spawning the prefab which has the script applied as I don't want it to be in the game yet. If I add the prefab into the game first, I can set the waypoints to the game objects.
How can I fix this so that I am able to add the waypoint game objects to the prefab in the assets?
you can have this method in movement script:
public void SetWayPoints(Transform[] waypoints)
{
this.wayPoints = waypoints;
}
And when you instantiate your prefab just get the component and set the way points;
GameObject baloon = Instantiate(baloonPrefab) as GameObject;
var movementScript = baloon.GetComponent<Movement>();
if(movementScript != null)
{
movementScript.SetWayPoints(waypoints);
}
Note that above code is just an example to illustrate the method of doing it. You script can vary depending on your implementation of waypoints. I assumed that waypoints is an array of transform within a movement script and baloon follows it one by one. Also spawner class have a reference of waypoints in hierarchy and you just pass that array from spawner.
Hope this helps.
Let me know if you have any problem.

Multiple Colliders on Complex Object

I have designed a complex city with thousand of objects like roads, sideways, buidlings, trees, etc. and imported to Unity3d
I want to put colliders over them, so that when player hit them, it should face collision and should not passes though them
Though it has many objects, if i put one by one collider to each object, it will take so much time. Is there any other way i can just select all of them and put collider.
Also, if i select all object and put colliders (Mesh Collider). it is not adding to the object
Please help
Editor Scripting to the rescue. I would write a tool similar to this example. It uses a Menu Item which can be selected via Window -> Collider Tool. It then runs our custom method to find all meshes, which we want to add a collider to, then adds one and also logs which GameObjects were changed.
using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
public static class ColliderTool
{
[MenuItem("Window/Collider Tool")]
public static void RunTool()
{
List<MeshFilter> meshes = findObjectsThatNeedColliders();
for (int i = 0; i < meshes.Count; i++)
{
GameObject go = meshes[i].gameObject;
// Add a collider to each mesh and record the undo step.
MeshCollider collider = Undo.AddComponent<MeshCollider>(go);
// Use the existing mesh as the collider mesh.
collider.sharedMesh = meshes[i].sharedMesh;
Debug.Log("Added a new collider on: " + go.name, go);
}
Debug.Log("Done");
}
private static List<MeshFilter> findObjectsThatNeedColliders()
{
// This list will be filled with all meshes, which require a collider.
List<MeshFilter> meshesWithoutCollider = new List<MeshFilter>();
// Get all meshes in the scene. This only returns active ones.
// Maybe we also need inactive ones, which we can get via GetRootGameObjects and GetComponent.
MeshFilter[] allMeshes = GameObject.FindObjectsOfType<MeshFilter>();
foreach(MeshFilter mesh in allMeshes)
{
if(mesh.GetComponent<Collider>() == null)
meshesWithoutCollider.Add(mesh);
}
return meshesWithoutCollider;
}
}
You might need more complex rules about which objects require a collider and which type it should be, but a simple tool can still save you a lot of time before hand tweaking everything.
You should also consider making this selection based. The Selection class can give you a list of all selected objects. Some ideas:
Add a MeshCollider to all selected objects, if one doesn't already exist.
Add a BoxCollider to selected objects and scale it to an approximate size depending on the transform size or bounding box of the MeshRenderer.
My solution is based on your question about how to add a collider to many objects in a large scene. However, this might not be the overall best solution. Maybe too many MeshColliders hurt physics performance. You will most likely want to approximate most of the colliders with boxes and spheres, but of course you can still write a tool to help you with that.

How to detect that my object is completely inside a box?

I'm developing a game that you drag and drop objects into boxes and I have no idea what's the best and most efficient way to detect whether my objects are in a box.
I'm well aware of colliders and I'm using BoxColliders and triggers to find out whether my object is touching a box but I want to detect the moment when my object (which we can assume to be sphere for sake of simplicity but later will be a mesh) is completely inside my box trigger/collider.
I read about "Contains" method of colliders but IIRC they just check if one single point inside that collider but I'm interested to know if the whole object is inside the collider.
Thanks in advance folks.
Short answer: If you want 100% accuracy, your algorithm will never be better than O(|V|) (worst case) where V = {all vertices in mesh}, meaning you'd run .Collides() over every vertex and break if you find one that is outside your container.
Longer answer: Several methods exist to subdivide mesh surfaces, examples include: KD-Trees, OcTrees. These are beyond the scope of an SO answer to provide a full implementation, I suggest you see the wiki pages for details.
You could use these methods to divide your mesh up in to smaller sets of vertices. To speed up your algorithm you would start at the root of your subdivision tree and test if that node is contained in your container box. Keep working through the tree until you find a node that is not contained by your box. This will allow your "contains" test to fail faster but ultimately you'll wind up testing every vertex if your box contains your mesh.
Caveat: This solution does not work if your mesh is animated. In that case your best bet is to use the bounds around things like arms, feet, legs, etc and use that information to cull your Contains() tests. Again, you'll end up having to test every vertex if the mesh is fully inside your box.
All boxes have a boxCollider. If an object touches the second box, the object must be inside the first box.
This is not a good solution but, maybe it will be usefull.
Use Renderer.bounds property to get bounding box of your object.
Depending on what object you have and how accurate you want to check it to be inside a collider you might than use one of the simple ways to determine that.
for a more refined and cleaner approach. this would be perfect for what you are doing .
you can check the distance between the object you are dragging and the box .
the box has a x,y,z value which represents its position in space.
so when you drag your gameobject it may be just 0.2 on the x,y, or z away from the centere of your box. so just use this method to calculate the distance between your dragged object and the box.
var other :Transform;
function Update()
{
var dist = Vector3.Distance(other.position, transform.position);
// while dragging
if(dist <10)// 10 being on all 3 axiz .
{
//dragged object.position = box position
}
if (dist == 0)
{
print("i am in the centre of the box");
}
}
thus your gameobject will be in the box .
The box within a box solution above is a good option, but if that won't work (due to variably sized/shaped objects) you might be able to accomplish something with Physics.Raycast or Collider.Raycast. I had a similar problem where I needed to test if arbitrary points were contained inside colliders (many of which were unusual blobby concave objects).
The basic idea is a "bed of nails" approach where I cast rays toward the point from multiple directions. If I hit the outside collider on all of the rays, then I can be pretty confident that the point is contained inside the collider (but still not completely certain). Here's a pic:
In this picture, we're trying to see if the blue point is inside the yellow collider. The GREEN arrows represent successful raycasts (the yellow collider is hit), and the PINK one is unsuccessful (the yellow collider is NOT hit).
Here is a code snippet illustrating this:
public static class CollisionUtils {
private static readonly Vector3[] raycastDirections;
// These are the directions that we shoot rays from to check the collider.
static UltrasoundCollisionUtils() {
raycastDirections = new Vector3[5];
raycastDirections[0] = new Vector3(0,1,0);
raycastDirections[1] = new Vector3(0,-1,-0);
raycastDirections[2] = new Vector3(0,0,1);
raycastDirections[3] = new Vector3(-1.41f, 0, -0.5f);
raycastDirections[4] = new Vector3(1.41f, 0, -0.5f);
}
public static bool IsContained (Vector3 targetPoint, Collider collider) {
// A quick check - if the bounds doesn't contain targetPoint, then it definitely can't be contained in the collider
if (!collider.bounds.Contains(targetPoint)) {
return false;
}
// The "100f * direction" is a magic number so that we
// start far enough from the point.
foreach (Vector3 direction in raycastDirections) {
Ray ray = new Ray(targetPoint - 100f * direction, direction);
RaycastHit dummyHit = new RaycastHit();
// dummyHit because collider.Raycast requires a RaycastHit
if (!collider.Raycast(ray, out dummyHit, 100f)) {
return false;
}
}
return true;
}
}
One way you could adapt this algorithm is rather than use Collider.Raycast, do a Physics.Raycast. If the rays hit anything other than your collider, then you know that your target object isn't entirely in the collider.
Add a BoxCollider which surrounds the whole of the object you are testing for and check its bounds min and max are contained within the BoxCollider its entering ... this may not suit for complex mesh objects but you may be able to get away with it and its cheap
Simply,
You can place a box Collider at the bottom of your container.. If your sphere or whatever object touches that then it is completely inside the container..
There is one method though....not that accurate but will work :
Make four empties with collider(Circle / Box) like four wheels of a car and make the object parent to these empty objects with collider.
Then assign every collider a bool whether it is touched or not....
Count the number of colliders touched along with the actual mesh collider...Roughly estimates the orientation of the overlap. If it is 2 that means touched or overlaped from sideways.
Ex: If two collider + the mesh collider is colliding which means it is overlapped sideways...
I solved it using bounds.contains(vector 3 point).
I placed a single point on the object to be detected, and once it was inside the checking limits, I was able to acknowledge its presence.
public class PointInsideBound : MonoBehaviour
{
public Collider BoundCollider;
private Transform pointToCheck;
private void OnTriggerEnter(Collider other)
{
if (pointToCheck == null)
{
//There is a point on top of the collided object. Getting the reference here.
pointToCheck = other.transform.GetChild(0);
}
}
private void OnTriggerStay(Collider other)
{
if (pointToCheck == null)
{
return;
}
if (BoundCollider.bounds.Contains(pointToCheck.position))
{
Debug.Log(" Point Inside the boxcollider");
BoundCollider.enabled = false;
}
}
}
You should use a collider. This is description. http://docs.unity3d.com/Documentation/ScriptReference/Collider.html