This question already has answers here:
Physics2D.OverlapCircleAll not detecting other gameobjects
(4 answers)
Closed 1 year ago.
I want to spawn some balls (with CircleCollider2d and static Rigidbody2D) with this code. I use a button to see if it works and when I use it everything is ok. But when I use a loop to create a bunch of balls in a single frame, they appear overlapping. I think it is because you have to wait for the physics to be updated, but I need to spawn all balls at the same time. Any ideas or solutions?
It is my first question and I do not speak English well, but I hope I have explained it well. Thanks a lot
public void CreatePointBall()
{
Vector2 pos;
float x, y;
int tries = 0;
do
{
tries++;
x = Random.Range(MIN_POS_X, MAX_POS_X);
y = Random.Range(MIN_POS_Y, MAX_POS_Y);
pos = new Vector2(x, y);
} while (Physics2D.OverlapCircle(pos, radius, LayerMask.GetMask("PointBall")) != null && tries < MAX_TRIES);
if(tries == MAX_TRIES) Debug.Log("MAX TRIES WITHOUT A CORRECT POS");
GameObject go = Instantiate(pointBallPrefab);
go.name = "PointBall";
go.transform.parent = transform;
go.transform.position = pos;
pointBallsList.Add(go);
}
You can try to use Physics.SyncTransforms. Or Physics.Simulate
Actually, it's not a good practice to do this, it can hurt the performance a lot.
If you not need to spawn spheres immediately, in a single frame, you can put your code into coroutine, and after spawning each ball, wait for physics update: yield return new WaitForFixedUpdate();
If all of your spheres has a same scale, you can easily use a math instead of physics. For this, you need just to check the distance from current point to all other points.
It can be expensive, if you have a really large amount of points - so you can optimize it, keeping your points sorted - if your points array is sorted, you only need to compare 2 distances, next larger and previous smaller. But it can be tricky to implement.
Also, if you'll compare many distances, do not use Vector2.magnitude - use Vector2.sqrMagnitude, it's much faster.
Related
I'm trying to do something like this in Unity - https://youtu.be/uLZvNNW_Xoc , where when I go through the checkpoint, I get the exact mathematical result (clones of the character) of the same character who passed it.
I tried to clone them manually so that I knew how the animation and the walk would be, but when I turned on the game, it all shattered, the characters started to run around and bounced off each other.
You can Clone GameObjects with GameObject.Instantiate()
More details here: https://docs.unity3d.com/ScriptReference/Object.Instantiate.html
You can try setting a specific position for each cloned GameObject, it sounds like u are cloning them too close to each other.
Here's a little example of what I mean:
GameObject characterToClone = GameObject.Find("NameOfYourCharacterGameObject");
for(int i = 0; i < amountOfClonesNeeded; i++)
{
Vector3 newPosition = characterToClone.transform.position + new Vector3(10, 0, 0);
characterToClone = GameObject.Instantiate(characterToClone, newPosition, Quaternion.identity);
}
Like this you can Clone your Character multiple times where every new Clone should be 10 units appart from the previos one! You probably have to adjust the offset yourself though to make it fit perfectly for your game.
I hope I was able to help you!
I'm trying to find other methods of registering collisions (other than OnCollisionEnter() and OnCollisionExit()). I'm currently using Physics.OverlapBox(), but I need more information about the collision; i.e., normal, point.
I can use Physics.BoxCast(), but the problem is that it moves a box a given distance, and using maxDistance = 0f won't work.
I need a method of checking for collisions similar to Physics.OverlapBox() except in that it would also return information about all collisions in the cast.
Any help is appreciated. Thanks.
Your concern, expressed in the comment to the first answer is valid, but the bad news is that there is no simple trick to go around it. What you should be looking for is called continuous collision detection with a simplified version described in my answer on a somewhat similar matter:
Basically, for each moving object in your scene you have to calculate
moment of next collision within the fraction of the frame 0<t0<1,
then advance positions to this moment t0 within the frame, update
velocities due to collision and proceed further to the next collision
t0<t1<1, until you reach time of tn=1 (end of frame), making sure
you don't get stuck in a the middle of the frame due to rounding of
calculation or "cornered" objects. For spherical colliders, that is
usually done by using capsule vs capsule (for pairs of objects)
intersection and capsule vs box for the boundaries.
In oppose to the simple engine from the answer I'm referring to, Unity has continuous collision detection.
So you can enable continuous collisions and continuous dynamic which computationally is very expensive.
You can also try using RigidBody.SweepTest which returns the closest collision information. Notice that even though there is also RigidBody.SweepTestAll, it doesn't help much. Not only because it returns only first 128 collisions, but also because it doesn't process them as there is no reflection. For physically correct behaviour you have to do what described above - advance time till the first collision and update velocities. Either with the physics engine or by yourself. This is very costly and not many games are doing that even cheating by using simplified objects (spheres are the cheapest ones as two swept spheres are two capsules and their intersection is a relatively cheap calculation), but amount of steps, especially in the "cornered" case when objects have nowhere to go and therefore are constantly colliding could be very large and such cases happen more than one can expect.
For complex objects you unlikely can do better than SweepTest, unless you trigger it based on the simpler primitives, such as Physics.BoxCast or Physics.SphereCast. Again, even though there are Physics.BoxCastAll and Physics.SphereCastAll they are not particularly useful as only first collision is guaranteed to occur. Those xxxCastAll are the functions you wrote you were looking for, so give it a try, they might work well enough for your use case.
You can use OverlapBox and use Collider's ClosestPoint to select a single point of overlap, and use that to make your collision calculations.
Collider[] cols = Physics.OverlapBox(...);
Vector3 myPosition = transform.position; // for example
foreach (Collider col in cols) {
Vector3 closestPoint = col.ClosestPoint(myPosition);
Vector3 positionDifference = (closestPoint-myPosition);
Vector3 overlapDirection = positionDifference.normalized;
}
This overlapDirection will point in the direction away from the the position you use in ClosestPoint to the center of each colliding collider. If you want something based on the surface of your object, what you can do is use that overlap direction to place a raycast aimed at your object, to find the normal that way:
// ...
foreach (Collider col in cols) {
Vector3 closestPoint = col.ClosestPoint(myPosition);
Vector3 positionDifference = (closestPoint-myPosition);
Vector3 overlapDirection = positionDifference.normalized;
RaycastHit hit;
int layerMask = 1; // Set to something that will only hit your object
float raycastDistance = 10.0; // something greater than your object's largest radius,
// so that the ray doesn't start inside of your object
Vector3 rayStart = myPosition + overlapDirection * raycastDistance;
Vector3 rayDirection = -overlapDirection ;
if (Physics.Raycast(rayStart, rayDirection, out hit, Mathf.Infinity, layerMask)) {
Debug.Log(hit.normal);
Debug.Log(hit.position);
} else {
// The ray missed your object, somehow.
// Most likely it started inside your object
// or there is a mistake in the layerMask
}
}
I am working on a system, which is distributing Commands from a HashSet to a Player. I want to distribute a Command to the Player, who is closest to the Command.
void AssignCommand(Player player, HashSet<Command> commandList) {
//Player assigned;
float min = float.MaxValue;
float dist;
foreach(Command command in commandList) {
dist = Vector3.Distance(command.Position, player.Position);
if(dist < min) {
//check if command already assigned to another player
assigned = command.assigned;
if(assigned != null) {
//reassign when distance is smaller
if(dist < command.Distance(assigned)) {
//mark previously assigned command as unassigned
if(player.activeCommand != null) player.activeCommand.assigned = null;
player.activeCommand = command;
command.assigned = player;
min = dist;
assigned.activeCommand = null;
AssignCommand(assigned, commandList);
}
}
else {
if(player.activeCommand != null) player.activeCommand.assigned = null;
player.activeCommand = command;
command.assigned = player;
min = dist;
}
}
}
}
My problem with this code is that if there are a lot of commands in the HashSet it takes quite a while and the framerate drops from ~60 to about ~30 fps on my machine. This is no surprise, because the Vector3.Distance method is just called for (every player) * (every command), which is way too much. I am looking now for a way to reduce the number of calls somehow to improve the performance. Any ideas here?
I also tried running this code in a different Thread, but I gave up, because this is changing and using too many Thread Unsafe values. My latest try brought me to the check if assigned != null throwing an error for comparing.
I would be very grateful for any hints either improving the overall speed of this code or how to run this in a ThreadPool. If required I can also post my JobClass I created for the Thread attempt.
All the threading solutions and optimizations are fine, but the biggest thing you want to keep in mind (for this and for the future) is: Do not use Vector3.Distance or Vector3.magnitude for this, ever. They are inefficient.
Instead, use Vector3.sqrMagnitude, which is the same thing (for distance comparison), without the sqrt (the most expensive part).
Another optimization is to write your own (square) distance calculation, throwing out the y value if you know you don't care about vertical distances. My distance comparison code was slow, so I tested this pretty carefully and found this is the fastest way (especially if you don't care about vertical positions): (EDIT: this was fastest in 2015. Test yourself for the fastest code on modern Unity.)
tempPosition = enemy.transform.position; // declared outside the loop, but AFAIK that shouldn't make any difference
float xD = targetPosition.x - tempPosition.x;
float yD = targetPosition.y - tempPosition.y; // optional
float zD = targetPosition.z - tempPosition.z;
float dist2 = xD*xD + yD*yD + zD*zD; // or xD*xD + zD*zD
Edit: Another optimization (that you're likely already doing) is to only recalculate when a player has moved. I like this one because it doesn't compromise the data at all.
I wrote my own version of System.Threading.Tasks for unity and added something like this for ordering workload based on distance from the camera.
Essentially whenever a task (or in your case command) was needed it passed off a position and the task to a TaskManager that would then each frame sort the items it had and run through them.
You could probably do the same / similar but instead of passing the command to some sort of CommmandManager like I did with a TaskManager do a lookup on creation and pass the command to the player closest to the point in question.
Most people these days are pulling their scene graphs in to something like a quad tree which should make finding the right player fairly fast then each player would be responsible for executing its own commands.
Okay after hours working on the issue I finally found a solution to improve the performance on the one hand and make it threadable on the other hand. I had problems with the threading, because player is a Unity object.. Instead of using the player object within the task I only get its position in the Start() method. Thus I managed to make it threadable, although it seemed strange to me, that I represented the players by its positions using Vector3 now.
Improving the performance did happen by adding another Dictionary storing the already calculated distances for each player. So when reassigning a player the distance did not need to be recalculated again... I am not sure how much of performance this brought, because I tested it together with the Thread, but at least I got rid of some calls of Distance and am back at stabel 60 fps!
Furthermore I messed something up with the recursions, so that I got up to 100.000 recursions for each player.. This should NOT happen o.O. The fix was easy enough. Simply added a minCommand command, which I set during the foreach and only assign commands and touch the Sets AFTER the foreach.. I bet the code would now run like sugar even without threading...
My question is about if there is a way to know the coordinates of the corners of a gameobject. What I have is three Vuforia AR targets and a gameobject, a cube in this case.
What I need to achieve, is so that when I move the targets around, the corners of the cube would follow the targets, eg. the cube would be as wide as the space between the targets.
Right now how it does it, is that it checks the distance between the targets and sets the scale of the cube according to it. This results in the cube being expanded always from its set position, which makes the positioning of the targets awkward in real life.
Here's a couple of pictures showing what it does now, taken during execution:
Here is the code attached to the cube-object:
using UnityEngine;
using System.Collections;
public class show : MonoBehaviour {
float distancex;
float distancez;
// Use this for initialization
void Start () {
renderer.enabled = false;
}
// Update is called once per frame
void Update () {
if (GameObject.Find ("target1").renderer.enabled && GameObject.Find ("target2").renderer.enabled &&
GameObject.Find ("target3").renderer.enabled && GameObject.Find ("target4").renderer.enabled)
{
renderer.enabled = true;
}
distancex = Vector3.Distance ((GameObject.Find ("target1").transform.position), (GameObject.Find ("target2").transform.position));
distancez = Vector3.Distance ((GameObject.Find ("target2").transform.position), (GameObject.Find ("target3").transform.position));
Debug.Log (distancex);
Debug.Log (distancez);
transform.localScale = new Vector3((distancex), transform.localScale.y, transform.localScale.z);
transform.localScale = new Vector3(transform.localScale.x, transform.localScale.y, (distancez));
Debug.Log (transform.localScale);
}
}
How do I make the corners of the object follow the targets? I need the width of the side to be the width of the distance between the targets, is there any way to achieve this without using the scale?
I know this is quite some time after you asked the question, but I came across this as I was looking to sort something similar out myself.
What I found I needed (and others may be helped) is to use Renderer.bounds
What it looks like in practice for me:
void Update () {
rend = currentGameObject.GetComponent<Renderer>();
Debug.Log(rend.bounds.max);
Debug.Log(rend.bounds.min);
}
My object in this case was a quad at position 0,0,200 and a scale of 200,200,1. The output of rend.bounds.max is (100.0,100.0,200.0) the min was (-100.0,-100.0,200.0). This gives you the corner position for each corner (granted my example was in 2D space, but this should work for 3d as well).
To get it a little more specific for your example if you wanted the top right corner, you could get the XY of renderer.bounds.max, for the top left you would get the renderer.bounds.max.y and the renderer.bounds.min.x. Hope that helps!
Cheers!
Create 8 empty game objects.
Make them children of the "cube" object to be tracked.
Move them in Editor to be at the 8 corners of your tracked game object. Since they are children of the tracked object, their positions will be {+/- 0.5, +/- 0.5, +/- 0.5}.
Name them memorably (i.e., "top-left-back corner").
These 8 objects will move and scale with the tracked object, staying at its corners. Any time you want to know where a corner is, simply reference one or more of the 8 game objects by name and get the Vector3 for each of their transform.position.
Note: If you're doing step 5 repeatedly, you may want to avoid potentially costly GameObject.Find() calls (or similar) each time. Do them once and save the 8 game objects in a variable.
I worked my way around the problem by determining the position between the targets and counting their mean.
This is not flawless, however, since it is difficult to determine the scale factor with which the models would accurately follow the targets' corners, when bringing external models to use with the system.
public void checkForCollision () {
int headX = cells[0].x;
int headY = cells[0].y;
int noOfParts = nPoints;
for(int i = 1; i <noOfParts;i++)
{
int tempX = cells[i].x;
int tempY = cells[i].y;
if(tempX == headX && tempY == headY){
JOptionPane.showMessageDialog(null,"Head hit body");
//EndGameCollectScore etc.
}
}
}
EDIT: 'Cells[]' is an array of type Point AND noOfParts is just how many segments the snake has
main Question
With the above code I'm trying to compare tempX to headX but i would like to have a sort of margin for error e.g. +-5 but am unsure how to accomplish this, my reasoning behind this is i'm thinking maybe the x and Y variables might be a few digits apart so if i have the radius of one of the segment of the snake (explanation of 'snake' in Alternate below) then if i'm right and the values are a tiny bit off it should still come back positive.
OR
Alternative
if anyone can suggest a better way for doing this? Basically it's for a Snake game and headX and headY is the head of the snake and the remaining X and Y variables in Cells is the body, and I'm attempting to compare if the head hits the body.
I tested it and it seemed to work but after i tested it again it seems it will only pick up the collision if i make the snake double back on itself for a few squares. e.g. IF i cross the body perpendicular it will not detect the collision.
Also i am fairly certain that this method is called after each block the snake moves.
Cheers,
Shane.
P.S Running of very little sleep and way too much sugar in my blood, If you need further clarification because the above doesn't make alot of sense let me know.
int eps = 5;
if (Math.abs(tempX - headX) <= eps && Math.abs(tempY - headY) <= eps) {
// ...
}
To check if two points are within a delta from each other, compute the distance between them. You can avoid going into the square root territory by using squares, like this:
int distSq = (tempX-headX)*(tempX-headX) + (tempY-headY)*(tempY-headY);
int minDist = 5;
if (distSq < minDist*minDist) {
// too close
}
I don't know how your snake looks, but if it has a complex shape, looking for a hit can be expensive in terms of speed. You can speed up collision detection if you can do a quick test, to see if a collision is possible at all. You can do this by using a bounding box. You would have to keep track of minimum and maximum x and y positions of the snake body. Only if a coordinate lies within these boundaries you would take account of the exact shape of the snake. How this has to be done depends on how the snake is represented. Check for each tile or each pixel the snake is made of or possibly check if the coordinate is within a polygon, if the snake outline is defined by a polygon. (I'm not going to explain how this works here, but you will find algorithms if you google a bit.)
If you need to calculate the distance to another point (the snake head), you can use different metrics for this. If only horizontal and vertical movements are possible within the game, the so called Manhattan or taxi distance can be used: d = |x1-x0| + |y1-y0|. It consists of adding the x and y distances, or you can use the maximum of both distances: d = Max(|x1-x0|, |y1-y0|) (correponds to 2kay's approach).
If you need the exact distance, apply the Pythagorean formula. In order to compare the distance with the error margin, you don't need to calculate the square root. Instead compare the square of the distance with the square of the error margin. This saves time. (x1-x0)^2 + (y1-y0)^2 < error_margin^2.