Bad usage of Physics.OverlapBox - unity3d

I don't understand the usage of method Physics.OverlapBox.
I want to put ten walls on a 4x4 plane in my scene. The width and location of the walls is calculated randomly. In the odd number of cycles in the creation loop the wall is rotated 90 degrees.
The walls presented in the scene should not collide with other walls... but it's not working.
void Reset()
{
int walls = 10;
for (int w = 0; w < walls; w++)
{
for (int i = 0; i < 5; i++)
{
float x = Random.Range(-20f, 20f);
float z = Random.Range(-20f, 20f);
Vector3 center = new Vector3(x, 1.51f, z);
int scalex = Random.Range(4, 13);
Quaternion quaternion = Quaternion.identity;
if (w % 2 == 1)
quaternion=Quaternion.Euler(0, 0, 0);
else
quaternion=Quaternion.Euler(0, 90, 0);
Collider[] colliders = Physics.OverlapBox(center, new Vector3(scalex, 3, 1) / 2, quaternion);
Debug.Log(colliders.Length);
if (colliders.Length == 0)
{
GameObject wall = GameObject.CreatePrimitive(PrimitiveType.Cube);
wall.transform.position = center;
wall.transform.localScale = new Vector3(scalex, 3, 1);
wall.transform.rotation = quaternion;
wall.tag = "wall";
break;
}
}
}
}

After your comment I think I now know what the issue is:
The physics engine simply doesn't "know" your walls colliders yet since the physics engine is updated in the next FixedUpdate.
You might want to call Physics.Simulate after each wall in order to manually trigger a physics update.
The docs are a bit unclear if it is necessary but you might have to disable Physics.autoSimulation before the loop and turn it back on after you are finished with the wall creation.

The solution proposed by derHugo (a lot of thanks) works from Start method. I added rotation to the walls. No collisions.
The code:
public void Start()
{
Physics.autoSimulation = false;
for (int i = 0; i < 200; i++)
{
createWall();
Physics.Simulate(Time.fixedDeltaTime);
}
Physics.autoSimulation = true;
}
void createWall()
{
float x = Random.Range(-20f, 20f);
float z = Random.Range(-20f, 20f);
Vector3 position = new Vector3(x, 1.51f, z);
Quaternion rotation = Quaternion.Euler(0, Random.Range(0,360), 0);
int scalex = Random.Range(2, 5);
Collider[] colliders = Physics.OverlapBox(position, new Vector3(scalex, 1, 1)/2, rotation);
if (colliders.Length==0)
{
GameObject wall = GameObject.CreatePrimitive(PrimitiveType.Cube);
wall.transform.localPosition = position;
wall.transform.localScale = new Vector3(scalex, 3, 1);
wall.transform.rotation = rotation;
wall.tag = "wall";
}
}

Related

Physics2D.OverLapBox detects objects that should be ignored

I'm using a script that looks at the tiles around my GameObject to see if it can detect a collider, through Physics2D.OverlapBox. My problem is that my Player should be ignored by the OverLapBox, as I've set it to look at layers it isn't in, but it is detected everytime.
My Player is in the "Default" layer.
private void SpawnBasicWalls()
{
int layersToScan = LayerMask.GetMask("Floor", "Wall");
//for each tile around this tile
for (int x = -1; x <= 1; x++)
{
for (int y = -1; y <= 1; y++)
{
Vector2 targetPos = new Vector2(transform.position.x + x, transform.position.y + y);
Collider2D hit = Physics2D.OverlapBox(targetPos, Vector2.one * 0.8f, layersToScan);
//if there isn't a tile around
if (!hit)
{
//Add a wall in that empty adjacent tile.
GameObject goWall = Instantiate(dungMan.wallPrefab, targetPos, Quaternion.identity) as GameObject;
goWall.name = dungMan.wallPrefab.name;
goWall.transform.SetParent(dungMan.transform);
}
else
{
Debug.Log(hit);
}
}
}
//Once it's done, the gameobject is useless and thus is destroyed
Destroy(gameObject);
}
If anyone can tell me what I'm doing wrong, I'd be very grateful.
Physics2D.OverlapBox(targetPos, Vector2.one * 0.8f, layersToScan) is basically calling Physics2D.OverlapBox(point, size, angle) - which means you are sending the layers (casted to int) as an angle.
You need to use one of the overloads that receive a layermask, and make sure you pass it in the right parameter.

Snapped GO's Rotation not working properly

I'm currently trying to snap objects (cubes, pyramids, torus) together. I assigned each face of the objects bounding box a "snap allowed" variable and on collision try to find the closest two sides to each other. I then move the main object to the collision side and rotate it accordingly.
The code is as follows:
private static Vector3[] sides = {
Vector3.up,
Vector3.forward,
Vector3.right,
Vector3.down,
Vector3.back,
Vector3.left
};
private void Snap() {
if (!snappedObject)
return;
if (lastSnapping > LeftController.GetLastSnappingToggle()) {
//we dont calculate new sides, only use the old ones
//but we have to check whether we are now further away
float dis = Vector3.Distance(GetWorldPositionFace(this.gameObject, lastSelf),
GetWorldPositionFace(snappedObject, lastOther));
float max = Mathf.Max(Mathf.Abs(size.x), Mathf.Max(Mathf.Abs(size.y), Mathf.Abs(size.z)));
if (dis > max)
return;
ApplyToOther(lastSelf, lastOther, snappedObject);
} else {
//we need to find both new closest sides
MeshSnapping other = snappedObject.GetComponent<MeshSnapping>();
float otherDis = float.MaxValue;
int otherSide = -1;
//find the closest side from the other object
for (int i = 0; i < NUM_SIDES; i++) {
float dis = Vector3.Distance(transform.position, GetWorldPositionFace(snappedObject, i));
if (dis < otherDis && other.sidesAllowed[i]) {
otherDis = dis;
otherSide = i;
}
}
//find the closest side of our object
float selfDis = float.MaxValue;
int selfSide = 0;
for (int i = 0; i < NUM_SIDES; i++) {
float dis = Vector3.Distance(GetWorldPositionFace(this.gameObject, i),
GetWorldPositionFace(snappedObject, otherSide));
if (dis < selfDis && sidesAllowed[i]) {
selfDis = dis;
selfSide = i;
}
}
//are we to far away or at a prohibited side?
float max = Mathf.Max(Mathf.Abs(size.x), Mathf.Max(Mathf.Abs(size.y), Mathf.Abs(size.z)));
if (selfDis > max)
return;
ApplyToOther(selfSide, otherSide, snappedObject);
//save the sides for next iteration
lastSelf = selfSide;
lastOther = otherSide;
}
lastSnapping = Time.time;
}
private void OnCollisionEnter(Collision collision) {
snappedObject = collision.gameObject;
}
private void OnCollisionExit(Collision collision) {
snappedObject = null;
}
private Vector3 GetWorldPositionFace(GameObject other, int i) {
//get the side in local coordinates, scaled to size
Vector3 otherLocalSize = other.transform.localScale;
Vector3 otherSidePoint = new Vector3(otherLocalSize.x * sides[i].x, otherLocalSize.y * sides[i].y, otherLocalSize.z * sides[i].z) / 2f;
//rotate it according to world position
Vector3 dir = (other.transform.rotation * otherSidePoint);
//actually move it to world position
Vector3 center = other.transform.position + dir;
return center;
}
private void ApplyToOther(int selfI, int otherI, GameObject other) {
//first get the midpoint of face of other go
Vector3 edge = GetWorldPositionFace(other, otherI);
Vector3 dir = edge - other.transform.position;
RotateSides(selfI, otherI, dir);
selfI = (selfI + NUM_SIDES / 2) % NUM_SIDES;
//get midpoint of face of self go
edge += GetWorldPositionFace(this.gameObject, selfI) - transform.position;
//now move towards the combination
transform.position = edge;
}
private void RotateSides(int selfI, int otherI, Vector3 dir) {
//rotate self side towards this point
switch (selfI) {
case 0: transform.up = -dir; break;
case 1: transform.forward = -dir; break;
case 2: transform.right = -dir; break;
case 3: transform.up = dir; break;
case 4: transform.forward = dir; break;
case 5: transform.right = dir; break;
}
}
I can find every midpoint of the bounding box by transforming the direction vector, applying the objects current rotation and position to it (see GetWorldPositionFace() ). After finding the best combination, ApplyToOther() moves the objects to position and rotates it according to the selected face normals. So far so good, but the result is not aligned. As you can see, the front faces do not face in the same direction, i.e. I want to rotate the upper cube around the transform.up axis by this amount. This would be the result that I want.
But, if I add
float angle = Vector3.Angle(transform.forward, snappedObject.transform.forward);
transform.Rotate(transform.up, angle);
to the RotateSides() function, the result is this. The rotation axis is wrong.
Using
Quaternion.FromToRotation(transform.up, snappedObject.transform.up)
did not work either.
What did I miss? Thanks for your help!
I figured out my problem. By setting the transform.forward and the transform.up seperately (e.g. with transform.rotate around axis), only one of them was correct. Using Quaternion.LookRotation() solves this.

How to draw a line over a specific duration using Vectrosity [duplicate]

I created a diagonal line renderer by attaching the following script to an empty game object. How can I extend the line at both ends for a half its length and how can I also extend the line by say 1 unit along the x-axis? Both over a certain period of time.
public class DiagonalLine : MonoBehaviour {
bool firstLineComplete = false;
LineRenderer diagLine;
public Vector3 startPoint = new Vector3 (0, 0, 0);
public Vector3 endPoint = new Vector3 (1.0f, 1.0f, 0);
public float lineDrawSpeed;
// Use this for initialization
void Start () {
diagLine = gameObject.AddComponent<LineRenderer>();
diagLine.material = new Material (Shader.Find ("Sprites/Default"));
diagLine.startColor = diagLine.endColor = Color.green;
diagLine.startWidth = diagLine.endWidth = 0.15f;
diagLine.SetPosition (0, startPoint);
diagLine.SetPosition (1, endPoint);
}
}
This is basic vector math.
You have the line with (from end to start):
Vector3 v = start - end;
and then you extend on each side by half if it:
extensionA = start + (v * 0.5f);
extensionB = end + (v * -0.5f);
If you need to extend by 1 then normalize:
Vector3 v = (start - end).normalized;
extensionA = start + v;
extensionB = end + (v * -1f);
Break your problem into pieces:
1.Extend line by x units on both sides:
This is done with the Ray class. Create a new Ray instance from the startPoint and endPoint variables then use the Ray.GetPoint function to extend the line. You have to do this on both sides to get the new extended lines.
A simple wrapper for the Ray class to simplify this:
Vector3 extendLine(Vector3 startPoint, Vector3 endPoint, ExtendDirection extendDirection, float extendDistance)
{
Ray ray = new Ray();
//Start
if (extendDirection == ExtendDirection.START_POINT)
{
ray.origin = startPoint;
ray.direction = startPoint - endPoint;
}
//End
else if (extendDirection == ExtendDirection.END_POINT)
{
ray.origin = endPoint;
ray.direction = endPoint - startPoint;
}
//Extend
Vector3 newUnityPoint = ray.GetPoint(extendDistance);
//Debug.DrawLine(ray.origin, newUnityPoint, Color.blue);
return newUnityPoint;
}
public enum ExtendDirection
{
START_POINT, END_POINT
}
Extend to the Left end
Vector3 newStartPos = extendLine(startPoint, endPoint, ExtendDirection.START_POINT, 4);
diagLine.SetPosition(0, newStartPos);
Extend to the Right end
Vector3 newEndPos = extendLine(startPoint, endPoint, ExtendDirection.END_POINT, 4);
diagLine.SetPosition(1, newEndPos);
2.For animating/moving it over time, use coroutine and Time.deltaTime. Increment a variable with Time.deltaTime every frame to then use Vector3.Lerp to lerp the from and to value.
See this function for example.
With both combined, below is a complete function to extend both lines over time:
bool isRunning = false;
IEnumerator extentLineOverTime(LineRenderer targetLineRenderer, float extendDistance, float duration)
{
//Calculate Left from extension length
Vector3 fromValLeftPos = targetLineRenderer.GetPosition(0);
//Calculate Right from extension length
Vector3 fromValRightPos = targetLineRenderer.GetPosition(1);
//Calculate Left to extension length
Vector3 newLeftPos = extendLine(fromValLeftPos, fromValRightPos, ExtendDirection.START_POINT, extendDistance);
//Calculate Right to extension length
Vector3 newRightPos = extendLine(fromValLeftPos, fromValRightPos, ExtendDirection.END_POINT, extendDistance);
//Make sure there is only one instance of this function running
if (isRunning)
{
yield break; ///exit if this is still running
}
isRunning = true;
float counter = 0;
while (counter < duration)
{
counter += Time.deltaTime;
//Move to left overtime
Vector3 tempLeftPos = Vector3.Lerp(fromValLeftPos, newLeftPos, counter / duration);
targetLineRenderer.SetPosition(0, tempLeftPos);
//Move to Right overtime
Vector3 tempRightPos = Vector3.Lerp(fromValRightPos, newRightPos, counter / duration);
targetLineRenderer.SetPosition(1, tempRightPos);
yield return null;
}
isRunning = false;
}
USAGE:
LineRenderer diagLine;
public Vector3 startPoint = new Vector3(0, 0, 0);
public Vector3 endPoint = new Vector3(1.0f, 1.0f, 0);
// Use this for initialization
void Start()
{
diagLine = gameObject.AddComponent<LineRenderer>();
diagLine.material = new Material(Shader.Find("Sprites/Default"));
diagLine.startColor = diagLine.endColor = Color.green;
diagLine.startWidth = diagLine.endWidth = 0.15f;
diagLine.SetPosition(0, startPoint);
diagLine.SetPosition(1, endPoint);
//Extend Line Over time
StartCoroutine(extentLineOverTime(diagLine, 4, 3));
}
The StartCoroutine(extentLineOverTime(diagLine, 4, 3)); will extend the line 4 units away from both sides within 3 seconds.

HoloLens Draw a graph

What is the best way to draw a graph for the HoloLens in unity?
I am new to this platform and have no idea which packages will work and which dont, the graph gets data dynamically.
EDIT: I have tried LineRenderer but it seems very limited in version 5.4 of Unity
A possible Solution for drawing a 3D-Graph is using a particle system:
Simple Example for a Component Script for a particle system:
public class Graph: MonoBehaviour {
//Particle-Resolution of the Graph
[Range(10, 100)]
public int resolution = 10;
private int currentResolution;
private ParticleSystem.Particle[] points;
void Start()
{
currentResolution = resolution;
points = new ParticleSystem.Particle[resolution];
float increment = 1f / (resolution - 1);
for (int i = 0; i < resolution; i++)
{
float x = i * increment;
points[i].position = new Vector3(x, 0f, 0f);
points[i].startColor = new Color(0f, 0f, 0f);
points[i].startSize = 0.1f;
}
}
void Update()
{
if ((currentResolution != resolution) || (points == null))
{
CreatePoints();
}
FunctionDelegate f = functionDelegates[(int)function];
for (int i = 0; i < points.Length; i++)
{
Vector3 p = points[i].position;
p.y = Sine(p.x);
points[i].position = p;
Color c = points[i].GetCurrentColor(GetComponent<ParticleSystem>());
c.g = p.y;
c.r = 1f - p.y;
points[i].startColor = c;
}
GetComponent<ParticleSystem>().SetParticles(points, points.Length);
}
private static float Sine(float x)
{
return 0.5f + 0.5f * Mathf.Sin(2 * Mathf.PI * x + Time.timeSinceLevelLoad);
}
}
A good tutorial for drawing 2D/3D graphs (including this example) with a particle system from CatLikeCoding (Jasper Flick). Refer to: http://catlikecoding.com/unity/tutorials/graphs/. It's a bit outdated and you must use startSize/startColor instead the depreceated color/size-Properties in this case.
But i'have testet it with the hololens allready and it worked fine. Some experiments with the HoloToolkit shaders for a better performance are necessary if you have a big amount of particles :-)
If you have further questions: Just ask me.

2D projectile trajectory prediction (unity3d)

(Using unity3d 4.3 2d, it uses box2d like physics).
I have problems with predicting trajectory
I'm using:
Vector2 startPos;
float power = 10.0f;
float interval = 1/30.0f;
GameObject[] ind;
void Start (){
transform.rigidbody2D.isKinematic = true;
ind = new GameObject[dots];
for(int i = 0; i<dots; i++){
GameObject dot = (GameObject)Instantiate(Dot);
dot.renderer.enabled = false;
ind[i] = dot;
}
}
void Update (){
if(shot) return;
if(Input.GetAxis("Fire1") == 1){
if(!aiming){
aiming = true;
startPos = Input.mousePosition;
ShowPath();
}
else{
CalculatePath();
}
}
else if(aiming && !shot){
transform.rigidbody2D.isKinematic = false;
transform.rigidbody2D.AddForce(GetForce(Input.mous ePosition));
shot = true;
aiming = false;
HidePath();
}
}
Vector2 GetForce(Vector3 mouse){
return (new Vector2(startPos.x, startPos.y)- new Vector2(mouse.x, mouse.y))*power;
}
void CalculatePath(){
ind[0].transform.position = transform.position; //set frist dot to ball position
Vector2 vel = GetForce(Input.mousePosition); //get velocity
for(int i = 1; i < dots; i++){
ind[i].renderer.enabled = true; //make them visible
Vector3 point = PathPoint(transform.position, vel, i); //get position of the dot
point.z = -1.0f;
ind[i].transform.position = point;
}
}
Vector2 PathPoint(Vector2 startP, Vector2 startVel, int n){
//Standard formula for trajectory prediction
float t = interval;
Vector2 stepVelocity = t*startVel;
Vector2 StepGravity = t*t*Physics.gravity;
Vector2 whattoreturn = ((startP + (n * stepVelocity)+(n*n+n)*StepGravity) * 0.5f);
return whattoreturn;
}
Using this, I get wrong trajectory.
1. It's like gravity doesn't drag trajectory down at all, and yes i know that gravity is weak because:
t*t*Physics.gravity = 0.03^2 * vector2(0, -9.8) = vector2(0, -0.00882)
But that is the formula :S
2. Since gravity is low, velocity is too strong.
Here is the video:
http://tinypic.com/player.php?v=1z50w3m&s=5
Trajectory formula form:
http://www.iforce2d.net/b2dtut/projected-trajectory
What should I do?
I found that if I set
StepGravity to something stronger like (0, -0.1)
and devide startVel by 8
I get nearly right trajectory, but i don't want that, I need true trajectory path.
Users from answer.unity3d.com said I should ask here, because here is a bigger group of mathematical coders.
And I searched a lot about this problem (that how I found that formula).
you're only calculating the effect of gravity over 1/30th of a second for each step - you need to do it cumulatively. Step 1 should end with a velocity of 0.09G, Step 2 with .18G, step3 with .27G etc.
Here's a very simple example that draws the ballistic trajectory based on start velocity and a supplied time:
using UnityEngine;
using System.Collections;
public class grav : MonoBehaviour {
public Vector3 StartVelocity;
public float PredictionTime;
private Vector3 G;
void OnDrawGizmos()
{
if (G == Vector3.zero)
{
// a hacky way of making sure this gets initialized in editor too...
// this assumes 60 samples / sec
G = new Vector3(0,-9.8f,0) / 360f;
}
Vector3 momentum = StartVelocity;
Vector3 pos = gameObject.transform.position;
Vector3 last = gameObject.transform.position;
for (int i = 0; i < (int) (PredictionTime * 60); i++)
{
momentum += G;
pos += momentum;
Gizmos.DrawLine(last, pos);
last = pos;
}
}
}
In you version you'd want draw your dots where I'm drawing the Gizmo, but it's the same idea unless I'm misunderstanding your problem.