How to find closest object without costing too much? - c#

I have searched the net and best possible way I found is this:
Transform GetClosestEnemy(Transform[] objects)
{
Transform BestTarget = null;
float ClosestDistance = float.MaxValue;
Vector3 currentPosition = transform.position;
foreach (Transform CurrentObject in objects)
{
Vector3 DifferenceToTarget = CurrentObject.position - currentPosition;
float DistanceToTarget = DifferenceToTarget.sqrMagnitude;
if (DistanceToTarget < ClosestDistance)
{
ClosestDistance = DistanceToTarget;
BestTarget = CurrentObject;
}
}
return BestTarget;
}
This seems the best way but my real question is, can I use Physics.SphereCast , OnCollisionStay or something to feed this function? I feel like they will be more expensive than just going through all of the possible objects. Is it true? How do these functions actually work?

The function is indeed very well written and optimized. However using Physics.SphereCast and OnCollisionStay to feed it would be nonsensical.
Physics.SphereCast is essentially a "thick" and more expensive raycast. It can tell you if an object with a collider is on its path, with a bit more detailed information about the first collider that was hit. Obviously finding the closest object if you only have one undermines needing an algorithm. If your underlying problem was to find the closest object in a particular direction it could solve it on its own.
There is a related function called Physics.SphereCastAll, which could make a bit more sense, since that one returns all objects in the path of the cast, but your question would have to be something along the line of "which object is closest to this unrelated point among all the objects in front this other point".
OnCollisionStay is individually called every physics timestep for every object with a collider and rigidbody that is in contact with the collider. It's no good for area selection, since it will actively push out all objects inside. You might have meant OnTriggerStay, which does work for an area, but is still not fitting for the problem. The nature of this method would require a bunch of memory to save what objects are in and a chunk of processing power since all that would be done every physics time step (0.03s by default), which is why I wouldn't even consider it. Personally I don't think it is even possible to solve your problem with OnCollisionStay, I would use a combination of OnCollisionEnter and OnCollisionExit if someone insisted on using triggers.
In my opinion the function that makes most sense is Physics.OverlapSphere. It returns an array of colliders within a specified radius. It could basically perform a physics based "prefiltering" so objects at the other end of the scene aren't even considered.
The following code shows an example on how you could use Physics.OverlapSphere to get a set of objects, convert them to transforms, pass them to your function and print the result.
Collider[] hitCollider = Physics.Overlaobjsphere(center, radius);
Transform[] objs = new Transform[hitCollider.Length];
for(int i=0; i<hitCollider.Length; i++){
objs[i] = hitCollider[i].transform;
}
Debug.Log(GetClosestEnemy(objs));
A small quirk is that Physics.OverlapSphere returns the Colliders and any given GameObject can have multiples of those. That means that we might be calculating the same object several times. In this case it is acceptable, since filtering them out will take more processing power than just running them thru another time.
The people that made the physics engine worked hard to optimize it. Nevertheless it can be expensive to involve physics. For example if you are going to check the same five objects over and over again doing a sphere overlap might not make sense. On the other hand if the objects of interest are instantiated and deleted all the time it might be unavoidable to use Physics to even gather a set to check against. For the average user these optimization considerations are unnecessary. Modern hardware usually has enough computational power. Never the less if you are curious you can always program a benchmark, repeating the algorithm a million times and measuring the time that it took using a Stopwatch.

Related

Raycast on a cube grid?

I am currently writing a Minecraft clone in Unity as my pet project, and I'm trying to implement raycasts for it, so that I can know which block the player looks at (I will use raycasts for other purposes too). The world of the game is a 3D grid of perfect unit cubes. Each element of a grid is either solid or not. I want to be able to shoot a ray from any point of my world and get the point where that ray hits the surface of a first solid block in it's way.
Here's a c# pseudocode of what my game aproximately looks like:
// An aproximation of what Unity's Vector3 looks like.
public struct Vector3
{
public float x, y, z;
}
public class World
{
public bool[,,] blocks;
public bool IsSolid(Vector3 pos) // i.e. if pos is inside a solid block
{
return blocks[Math.Floor(pos.x), Math.Floor(pos.y), Math.Floor(pos.z)]
}
public Vector3 Raycast(Vector3 origin, Vector3 direction)
{
// some algorithm, that returns the point at which ray hits a solid block
}
}
Note, that coordintaes of any Vector3 may not be whole nubers, it is entirely possible for rays to start (or end) at fractional coordinates. For simplicity you may (or may not) assume that world is infinite and a ray will always hit some block eventually. Remeber, that Raycast() should return the point at which the ray hits the surface of a cube.
What is the best algorithm I can use for this?
My priorities (in order) are:
Speed - making a raycast should be fast
Elegance - the algorithm should reasonably straightforward and concise
Generality - the algorithm should be easy to modify (i.e. add some extra functionality to it.)
Here's a Q/A for some possible questions:
Q: Why not use Unity's native colliders and raycasts?
A: Unity's colliders and raycast are too slow and aren't optimized for my needs, furthermore, that is by no means elegant of generic.
Q: Do you want an implementation of an algorithm or just the basic concept?
A: I'm fine with just understanding the basis of an aglorithm, but I would really apreciate an implementaion (preferably in C#).
Here are some basic principles. You will need to be fairly comfortable with linear algebra to even attempt this, and read and understand how ray-plane intersection works.
Your ray will start inside a cube, and it will hit one of the 6 faces on its way out of the cube. In normal cases we can quickly eliminate three of the faces by just checking if the ray direction points in the same direction as the cube-face. This is done by checking the sign of the dot product between the vectors. To find the first hit of the three remaining faces we do an intersection test to the corresponding plane, and pick the closest one, if you know the hit face you know what cube it hit. If that cube is empty you repeat the process until you find a non-empty cube. You may also add some checks to avoid edge cases, like eliminating all planes that are parallel to your ray as early as possible.
However, to get any real speed you really need some kind of tree structure to reduce the number of checks done. There are many alternatives, kd-trees, r-trees etc, but in this specific case I would probably consider a sparse octree. This means your cubes will be part of larger 2x2x2 sections, where the whole section can be tagged as empty, filled, partial filled etc. These sections will also be grouped into larger 2x2x2 sections and so on, until you hit some max size that either contains your entire play area, or one independently loadable unit of your play area, and have some logic to test multiple units if needed.
Raycasting is done more or less the same way with a octree as in the simple case, except you now have variable sized cubes. And when you hit a face you need to traverse the tree to find the next cube to test.
But to actually make a well optimized implementation of this requires quite a bit of experience, both in the concepts involved, and in the language and hardware. You may also need insight in the structure of your actual game-world, since there might be non obvious shortcuts you can take that significantly help speedup performance. So it is not guaranteed that your implementation will be faster than unitys built in.

"ArgumentException: The object you want to instantiate is null" Unity and i can't figure out why

This suddenly stopped working, when trying to instantiate the projectile is tells me the projectile is null. Even though i declare a value to it. The Debug tells me Start() is run. Can't give much more context.
The question here is not "what does this error mean" it's "why is it null?" I got a great reply from Daedalus who told me to stay away from string lookups. I will try that and tell y'all if that worked.
EDIT:// My teacher added some code in the text that i forgot to remove (he couldn't find out why i was getting null) it is however removed now and this is the correct code that does not work. The tag is not miss-spelled, I have checked the casing etc.
void Start()
{
targPlayer = GameObject.FindGameObjectWithTag("Player").transform;
projectile = GameObject.Find("Projectile");
Debug.Log("was run");
}
void Update()
{
fire -= Time.deltaTime;
dmg -= Time.deltaTime;
if (fire <= 0)
{
if (Vector2.Distance(transform.position, targPlayer.position) <= detectionRange)
{
// This is where the error happens
Instantiate(projectile, transform.position, Quaternion.identity);
}
fire = fireRate;
}
if (Vector2.Distance(targPlayer.position, transform.position) <= detectionRange && Vector2.Distance(targPlayer.position, transform.position) >= stopRange)
{
transform.position = Vector2.MoveTowards(transform.position, targPlayer.position, movSpeed * Time.deltaTime);
}
}
There are many possible solutions here, so I'll go through a handful which come to mind.
First off, lookups with strings are one thing I imagine most developers would call objectively bad. Putting case and culture issues for comparison aside, it's incredibly easy to make a typo, for you or another team member to later change the name of that object without remembering that these lookups are reliant on it, and when used in non-trivial cases, there are serious performance concerns. This is especially true of Unity, which will simply iterate through the hierarchy until it finds a matching object, for essentially all of the find calls.
Something like the above must have happened if your instantiate call is failing.
You will likely want to look into object pooling at some point, but let's proceed with the instantiation calls.
To get around the string lookups, you can make the projectile a variable.
public Transform projectile;
This will allow you to assign it in the inspector. It's likely that no other scripts should be allowed to access this variable, so for bonus points, you can use the SerializeField attribute to serialise a private variable, and assign it in the inspector.
[SerializeField] private Transform projectile;
You will then have immediate access to the projectile without any lookup overhead, and without the worry of breaking the lookups.
Your design philosophy will surely change a lot as you progress, and I'd argue that you shouldn't be tying any of this sort of data to logical classes (just in case anybody mentions this), but I'd say it's a good step in the right direction to begin by changing your lookup structure.

XNA how to write a good collision algorithm?

I'm currently working on a new game in XNA and I'm just setting basic stuff up like sprites/animations, input, game objects etc.
Meanwhile I'm trying to think of a good way to detect collisions for all the game objects, but I can't really think of a fast algorithm, which limits the game to very few objects.
This is what I did in my last project that was a school assignment
public static void UpdateCollisions()
{
//Empty the list
AllCollisions.Clear();
//Find all intersections between collision rectangles in the game
for (int a = 0; a < AllGameObjectsWithCollision.Count; a++)
{
GameObject obja = AllGameObjectsWithCollision[a];
for (int b = a; b < AllGameObjectsWithCollision.Count; b++)
{
GameObject objb = AllGameObjectsWithCollision[b];
if (obja.Mask != null & objb.Mask!= null && obja != objb && !Exclude(new Collision(obja, objb)))
{
if (obja.Mask.CollisionRectangle.Intersects(objb.Mask.CollisionRectangle))
AllCollisions.Add(new Collision(obja, objb));
}
}
}
}
So it checks for all collisions between all objects, but excludes adding collisions I found unnecessary.
To then inform my objects that they are colliding, I used a virtual method OnCollision that I called like this
//Look for collisions for this entity and if a collision is found, call the OnCollision method in this entity
var entityCol = FindCollision(entity);
if (entityCol != null)
{
if (entityCol.Other == entity)
entityCol = new Collision(entity, entityCol.Obj1);
entity.OnCollision(entityCol);
}
Collision FindCollision(GameObject obj)
{
Collision collision = AllCollisions.Find(delegate (Collision col) { return (GameObject)col.Obj1 == obj || (GameObject)col.Other == obj; });
return collision;
}
This made my game run slower fairly quickly when the amount of gameobjects increased.
The first thing that pop ups in my head is to create new threads, would that be a good idea & how would I do that in a good way?
I have studied algorithms a little bit so I know basic concepts and how ordo works.
I'm fairly new to c# and programming overall, so don't go too advanced without explaining it. I learn quick though.
There are quite a few things you can do:
The nested for loops produce a quadratic running time, which grows rather quickly as the number of objects increase. Instead, you could use some acceleration data structures (e.g. grids, kd-trees, BVHs). These allow you to reduce the intersection checks to only the entities that can potentially intersect.
If you can order your entities, you can reduce the collision checks by half by just checking entity pairs, where the second is "greater" (with respect to the order) than the first. I.e. you do not need to check b-a if you already checked a-b.
This part can be potentially slow:
!Exclude(new Collision(obja, objb)))
If Collision is a class, then this will always allocate new memory on the heap and recycle it eventually. So it might be better to make Collision a struct (if it is not already) or pass obja and objb directly to Exclude(). This also applies to your other uses of Collision. You haven't shown the implementation of Exclude() but if it is a simple linear search, this can be improved (e.g. if you search linearly in a list that contains an entry for every object, you already have a cubic running time for just the loops).
The implementation of FindCollision() is most likely a linear search (depending on what AllCollisions is) and it can get quite slow. Why are you storing the collisions anyway? Couldn't you just call OnCollision() as soon as you found the collision? A different data structure (e.g. a hash map) would be more appropriate if you want to check if a collision is associated with a specific entity efficiently.
Finally, parallelizing things is surely a viable option. However, this is somewhat involved and I would advice to focus on the basics first. If done correctly, you can reduce your cubic running time to n log n or even n.

Unity. Attempting fake internal ship gravity. Rigid body children of rotating object keep sliding around

I'm attempting to simulate a ship/space station with internal gravity.
To accomplish this, I'm making the player and all contents of the ship children of the ship. The ship itself has colliders, but no rigid body components. The idea is that as the ship moves, so will all of its contents. Pretty straightforward so far.
To simulate gravity in the ship, the player controller and all rigid bodies have the default gravity turned off. Instead of the standard, each frame a force is applied along the negative up vector of the parent ship.
This sort of works, but there is one major problem that I have to sort out before this thing is solid. All rigid bodies slide around the interior of the ship very slowly.
I'm aware that this is probably due to the updated position of the floor combined with the gravity force resulting in some kind of shear force. The objects always slide against the rotation of the ship.
I've tried mucking around with all of the physics properties from Physic materials to drag to mass, etc. None of these have worked, and I'm pretty sure it's due to the fundamental fact that the floor is moving, even though the RBs are children of the object that the floor is a part of.
Anyone have a solution to this that isn't some kind of duct tape? I could try to make everything kinematic and only "wake up" when certain external collisions occur or something, but that could get very cumbersome. I need for this to work in as much of a general purpose way as possible.
Some code:
On the ship
void Update ()
{
transform.Rotate(new Vector3(Time.deltaTime * 0.125f,Time.deltaTime*0.5f,0));
}
void FixedUpdate()
{
Vector3 tempVec;
foreach(Rigidbody rb in rigidBodies)
{
//Gravity!!
tempVec = transform.up * -9.81f * rb.mass * Time.deltaTime;
rb.AddForce(tempVec, ForceMode.Acceleration);
}
}
I've also worked on a version where the ship was following the movements of a rigid body. I couldn't do direct parenting, so I had to simply set the transform manually each frame to match the physics proxy. This still had the same effect as above, though it's probably ultimately how I want to move the ship, since that will tie into the flight mechanics more properly.
If you equate this to a real world scenario, the only thing that stops us from sliding around on the floor is friction.
Does the Physics library correctly apply friction based on the contacting materials? If not applying a certain amount of friction (or a minimum amount of force applied required to overcome it) should have the effect of preventing you from sliding around on the floor.
Although this is pretty much "duct tape" as above, it could neatly fit in and expand your physics engine if it doesn't already contain a way to enforce it.
As suggested above, the issue is because of how the physics engine applies friction. If I'm not mistaken, there will be some other forces acting on objects in a rotating frame (some of which are very unintuitive - check out this video: https://www.youtube.com/watch?v=bJ_seXo-Enc). However, despite all that (plus likely rounding errors arising from the engine itself and the joys of floating-point mathematics), in the real world, static friction is greater than moving (kinetic) friction. I don't think this is often implemented in game physics engines, which is why we so often see "wobbly" near-static objects. Also, you may run into the issue that even if this is implemented, the physics engine may be interpreting two contacting rotating bodies as non-static (even though their contact surfaces are static from a local perspective, the engine may be thinking globally)... [Insert joke about Newton and Einstein arguing].
https://i.stack.imgur.com/AMDr2.gif shows an idealised version of what friction actually looks like in the real world: until you overcome the static friction, nothing moves.
One way you would implement this (if you can access the physics engine that low-level) would be to round all movement forces below a certain threshold to zero - i.e. force < 0.001* is set to 0 (or possibly velocity < 0.001 is set to zero - whichever is easier).
*Some threshold - you'll have to work out what this is.
Otherwise, maybe you could instruct those objects to stop calculating physics and "stick" them to the parent surface, until such time as you want to do something with them? (This is probably a bad solution, but most of the other ideas above rely on hacking the underlying physics code).

2D Rectangle collision detection system (that works in a real game)

I have been developing a game in my spare time for the past few months. One sticking point that I have reimplemented over and over and not got 100% working is the collision detection. My system (posted below) mostly works however random things seem to happen from time to time, like the player being pushed outside the bounds of the level etc. Tutorials on the matter I have come across seem to offer basic workings, i.e, you have to know an object will be in relation to the object in question, but in a real game you wouldn't really know this. Here is my implementation but what I am after is if anyone knows of a good solid system for achieving what I am doing here.
Note that item comes from a collection of IItem which exposes the Rectangle and a few other bits for each item.
public void Move(float xAdditional, float yAdditional)
{
X += xAdditional;
Y += yAdditional;
foreach (var item in Level.Items)
{
if (item != this)
{
if (item.Boundary.Intersects(this.Boundary))
{
if (item.Boundary.Top > this.Boundary.Top) //we have collided with an object below us.
{
Y = item.Boundary.Top - (this.Boundary.Height/2);
}
if(item.Boundary.Bottom < this.Boundary.Bottom)//we have collided with an object above us.
{
Y = item.Boundary.Bottom + (this.Boundary.Height/2);
}
if(item.Boundary.Left > this.Boundary.Left) //We have collided with an object to the right.
{
X = item.Boundary.Left - (this.Boundary.Width/2);
}
if(item.Boundary.Right < this.Boundary.Right)// We have collided with an object to the left;
{
X = item.Boundary.Right + (this.Boundary.Width/2);
}
}
}
}
}
The final solution was to drop my own solution and implement Farseer.
Thanks
After some time with it I then opted for physics2d.net which I have found much more usable from a developers point of view.
First of all, Collision Detection depends heavily on the object geometry.
There are multiple proven to work solutions cast into linear algebra math,
but they are dependent on the geometries you try to use. Rather than
implementing an algorithm using your object's properties try to implement a mathematic equation directly and then use the result to determine if your collision happened or not. (like using vectors t = a-b, if |t|>0 collision, else not).
If you have a simple geometry like rectangles or circles you should take a
look into 'Mathematics for 3d game programming & computer graphics' by Eric
Lengyel.
Also keep in mind that you can achieve collision detection with other methods
like sprite collision. Another possibility is to use a higher level framework
doing this work for you (e.g. OSG)

Categories

Resources