I am trying to do exactly what this name of this thread says. I found this on unity answers: Anyway to tell which side of a collider is hit? - Questions & Answers - Unity Discussions and followed the instructions given. Right now it only kind of works but it is very inaccurate and seems like it just gives me a random output in the console when I test it. I would like to request help fixing my code.
This is my code:
transform the point to the local space of the collider (transform.worldToLocalMatrix).
Compare point to the ācenterā and āsizeā properties to figure out which side itās on. What should happen is one of the x,y,z values of (point - center) should be slightly equal (given float error) to the absolute value of the size x,y,z valuesā¦ the sign will denote which one of the two sides on the axes.
As for labeling sidesā¦ thatās up to you. Thereās no given ālabelā to a side.
You lost me at "Compare point to the ācenterā and āsizeā properties to figure out which side itās on. "
I am still trying to figure out what all is happening. I am not used to working with colliders.
a BoxCollider has 2 properties that define the extents of the box.
center - the position of the center of the box relative to the GameObject itās attached to:
size - the extents of the box relative to center:
This of course is in LOCAL space to the GameObject the BoxCollider is attached. Your Raycast hit point is in GLOBAL space, so you need to transform it to LOCAL space. This is done with the āworldToLocalMatrixā property of the transform on the GameObject the BoxCollider is attached to.
By doing this youāll have the point relative to the origin of the GameObject, just like the ācenterā and āsizeā properties.
Nowā¦ if you subtract ācenterā from the point, you have the point relative to the center of the box.
(point = point - box.center)
If the point is truly on the surface of the box, then one of its x,y,z values will be equal (ish, considering float error) to one of the size x,y,z values because itās on the surface. Just figure out which one it is.
considering that I donāt have a clue as to how collider calculations work. What I am getting from this is you convert the point where the ray hits to local space. Then subtract that local point from the center point of collider box and I should get a value that is close to the face of one side of the collider. I then compare that point coords on the face to the size coords. Is this correct or am I just rambling nonsense. I am trying to also learn and understand what is happening so I am not just copying code. I am more of a visual person so I could also use a coded example so I can visually see what you are trying to say.
what? how do I subtract vectors? Also dont I need to cast a ray to get the hit point? I am using the Ray cast to Select what enemy I want to attack, so I figured I might as well kill two birds with one stone and get the side of the box collider hit to determine how the character attacks the enemy.
If you have ever heard of the game āFire Emblemā, keep its game play mechanics in mind. for example, when I move a character near an enemy and click It, I want to know what kind of attack the player intends to do. Given that the enemy has not spotted the character attacking, If the character is close enough they can click the back side of the box collider of the enemy and preform a sneak attack from behind for a critical hit.
OK, so yeah, you donāt really need to do all thisā¦ you just need to know in what direction they clicked. Like BoredMormon suggested.
But so far it appears you donāt understand how vectors work at allā¦ so even resolving that information is going to take a bit of splainingā¦ you aught to go and learn about vectors before proceeding. Theyāre kind of CRITICAL to game programming.
It is 3D. Also arenāt vector2ās used for 2D x,y coordinates and vector3ās used for 3D x,y,z coordinates. I somewhat know how they work. For example I use an array of vector3ās to instantuate my characters into the scene upon loading.
After a lot of trial and error I finally got it to work. This is my solution:
if (Input.GetMouseButtonDown (0)) {
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast (ray, out hit, DetectCharacterSelect.SelectedPlayer.GetComponent<CharacterSheet>().CurrentClass.Range)) {
if (hit.transform.tag == "Enemy") {
selectedEnemy = hit.collider.transform.gameObject;
BoxCollider box = hit.collider as BoxCollider;
if (box == null) Debug.LogWarning("Collider is not a BoxCollider!");
Vector3 Normal = hit.normal;
Normal = hit.transform.TransformDirection( Normal );
if( Normal == hit.transform.up ){
Debug.Log("Arial Attack Above Enemy");
}else if( Normal == -hit.transform.up ){
Debug.Log ("Sneak Attck Below Enemy");
}else if( Normal == hit.transform.forward ){
Debug.Log("Direct Attack Infront of Enemy");
}else if( Normal == -hit.transform.forward ){
Debug.Log("Unaware Attack Behind Enemy");
}else if( Normal == hit.transform.right ){
Debug.Log("Flank Attack To The Right");
}else if( Normal == -hit.transform.right ){
Debug.Log("Flank Attack To The Left");
}else
}
}
}
Is there a way to fix it if the collider is for example turned 90 degrees on the y axis? I tried testing it to see if it still works with the collider rotated on the y axis and only the top and bottom work. I should also say that in my game it is only going to spin on the y axis so a fix for x and z is not necessary.
Iām actually amazed if this works without problems, and doesnāt run into floating point precision issues at some point.
What you want to do is calculate the dot product between the normal and the up vector.
float dot = Vector3.Dot(Normal, hit.transform.up;
If the normal and the up vector are pointing in the same direction, this value will be 1. You should probably give it a fudge factor in case theyāre not completely equal, so for example if dot > 0.99, you consider them to point the same direction.
Ok if I do this how would I correctly compare things to determine the side? By going back to comparing dots this puts me back where I started.
This is what I have:
it will either come out with an output of above or below because dotUp will always have a value. I would have to compare it to the other dots to make sure I am getting the correct ouput. This I believe is the problem I originally had. How would I go about comparing the dots?
EDIT
Actually this works because if the dot is zero if itās no the correct face, but it breaks after I try testing the rotation of the collider.
if(dotUp < 0){
//Below
Debug.Log ("Sneak Attck Below Enemy");
}else if(dotUp > 0){
//Above
Debug.Log("Arial Attack Above Enemy");
}else if (dotForward < 0){
//behind
Debug.Log("Unaware Attack Behind Enemy");
}else if(dotForward > 0){
//front
Debug.Log("Direct Attack Infront of Enemy");
}else if (dotRight < 0){
//Left
Debug.Log("Flank Attack To The Left");
}else if (dotRight > 0){
//Right
Debug.Log("Flank Attack To The Right");
}
Donāt compare like that. Remember that the dot product is 1 when they are pointing in the same direction, so you should be comparing it to 1. But as I said, they might not be exactly in the same direction, so check if itās greater than for example 0.99.
And when itās in the opposite direction, itās -1, so donāt just check if itās below 0, but check if it is for example below -0.99.
The exact value you compare with will depend on your game, and how precisely you need them to be in the same (or opposite) direction.
The dot product is 0 when they are exactly perpendicular, so when you compare with <> 0, it will be true almost always, just not when they are exactly perpendicular.
I am sorry to once again bother you. It does work when rotated, but say I click the back of the enemy then it turns 180 degrees. I click the enemy again but it still says I clicked the back although it now should be the front. Is there a way to mark and store the data of a box collider face on say Awake() and use those whenever the enemy rotates so I get the correct face? I have also come to another idea of having 6 colliders for each side of the enemy, but although it is simple, I really donāt think it is practical .