- Home /
How to prevent Transform from going through walls?
I have code when I press arrow keys my capsule transform instantly turns to desired direction and then moves in that direction. All that works good but when I'm in tight space between two skinny walls and I press key to turn it will sick through that wall and if I keep holding the key down it will eventually wobble through the wall and to the other side.
What I'm trying to achieve is to have the capsule be only able to turn and move in open direction - kind of like submarine in narrow space.(if it makes any sense)
I have Colliers on both of them - tried Rigid bodies and changing collision detection but nothing seems to work.
Here is part of my code.
if (Input.GetKey ("down"))
{
transform.eulerAngles = Vector3(0, 0, 90);
transform.Translate(Vector3.right * moveSpeed);
}
Thank you for any suggestions.
You posted a comment as an answer. Please see the FAQ on how this site works. Glad to see so many new users of Unity Answers
Answer by RyanZimmerman87 · Jul 27, 2013 at 03:29 AM
In my experience the best way to deal with this kind of thing is to use Physics.RayCast out the front of your gameObject (assuming the object is always facing the direction it is moving).
You will also need a RayCastHit variable to determine what your raycast hit if anything. You also may need to ignore certain colliders with a layerMask so that your ray only hits the objects you want to test for.
Example:
Ray rayForward = new Ray (playerTransform.position, playerTransform.forward);
RaycastHit rayHitForward;
GameObject rayHitForwardObject;
string rayHitString;
void Update()
{
//1.75 is the distance you want to stop moving if u hit wall
if (Physics.Raycast(rayForward, out rayHitForward, 1.75f))
{
rayHitForwardObject = rayHitForward.collider.gameObject;
rayHitString = rayHitObject.name;
}
if (rayHitString.name == "Wall")
{
//disable your forward movement
}
}
Answer by TSRajesh · Jul 27, 2013 at 07:03 AM
I tried raycasting in the direction that i move. It works fairly OK.. But If the ray misses, then part of our character gets into teh cube.. For that i had to use 5 raycasts .. From teh 4 corners of my bounding box and the centre, and if even one of them hits, then don't move. But this doesn't work while rotating.. It just slices into teh cube. After a lot of trial and error, I just found the method that works to my satisfaction.. Ghost object
I instantiate a cube of teh same sie of my mesh bounds, and make it invisible. So, whenever i want to move, or turn, or fall, I first move teh ghost object, and check if it collides with anything, If not, then proceed with teh rotation... I make similar calls for Moving and falling (in different contexts)
public bool CharCtrlExtRotColliding(Quaternion rot)
{
bool retval = false;
Quaternion oldRot = ghostChar.transform.rotation;
var hitColliders = Physics.OverlapSphere(ghostChar.GetComponent<MeshRenderer>().transform.position, _extents.z + _extents.x, ~(1 << LayerMask.NameToLayer("Ignore Raycast")));
for (var i = 0; i < hitColliders.Length; i++)
{
if (hitColliders[i].collider.gameObject.tag == "Floor") continue; //ToDo: Put Floor in layer to ignore raycast
ghostChar.transform.rotation = rot;
if (ghostChar.GetComponent<MeshRenderer>().bounds.Intersects(hitColliders[i].bounds))
retval = true;
}
ghostChar.transform.rotation = oldRot;
return retval;
}
That's an interesting idea with the ghost character. $$anonymous$$ight try something like that on a future project. It really just depends on what kind of game you are making which method would be most suitable.
$$anonymous$$y current project is aimed for Android/iOS so the controls are simple enough that just one forward raycast works with the tap screen aim.
But on my previous FPS PC game it was definitely more tricky. I think I actually ended up using a concept similar to the ghost char except ins$$anonymous$$d of testing before the player moves it would save the player's position from the previous update frame so if they ever got in a position they shouldn't be during an Update() frame it would reset them to the last one.
Always interesting to hear how people handle different problems lot's of great ideas on these forums!
Thank you guys I will look into that. The only thing is I don't know much about ray-casting so I will have to learn more about it.
Could I possibly use Vector3.Distance ins$$anonymous$$d of ray?
this would probably have to check for distance between every block with tag "wall" and capsule - unless I set small distance radius to check for. Just brainstor$$anonymous$$g.
To use Vector3.Distance, You must already have the blocking object reference. Not just "Any Object"... And, Learning to raycast (or spherecast or OverlapSphere etc) really takes no time at all even for an absolute newbie. Believe me, I just was there..
(Sorry for hijacking this thread.. ) @Ryan, I was wondering if you can answer me.. as you said that you did something similar to $$anonymous$$e.. When i check for intersection on bounding box, it is AABB - Axis-Aligned bounding box. So, I end up at a farther distance than absolutely necessary if my character is not Axis-Aligned. How did you check for mesh intersections? (OnCollider/Triggerxxx is out.. I want to know it in the very next line, not after a fixedupdate)
To be honest I was very new to Unity and program$$anonymous$$g when I was working on the PC FPS game. I'm still somewhat new to all this haha. I can take a quick look at the player move script from that project though let me see.
I can post the code I'm not sure if it will help though it's been so long and there may be much better solutions.
void OnCollisionEnter(Collision theCollision)
{
GroundScript otherObjectsScriptGround = theCollision.gameObject.GetComponent<GroundScript>();
WallScript otherObjectsScriptWall = theCollision.gameObject.GetComponent<WallScript>();
if (otherObjectsScriptGround != null)
{
playerGroundedBool = true;
}
if (otherObjectsScriptWall !=null)
{
transformCurrentSpeed = transformWalkSpeed;
playerSprintBool = false;
playerWallBool = true;
}
}
void OnCollisionExit(Collision theCollision)
{
GroundScript otherObjectsScriptGround = theCollision.gameObject.GetComponent<GroundScript>();
WallScript otherObjectsScriptWall = theCollision.gameObject.GetComponent<WallScript>();
if (otherObjectsScriptGround != null)
{
playerGroundedBool = false;
}
if (otherObjectsScriptWall !=null)
{
playerWallBool = false;
}
}
I'm a bit confused looking at that code now, some of the code I thought I was still using is commented out so I don't quite remember exactly what I was doing. But the collision stuff above is how I detected whether I was grounded or against a wall and you could potentially use that to reset your position to the last position with your desired bool conditions.
I would suggest changing that otherObjectsScript stuff to just be theCollision.name though, like I said I was pretty new when I was working on that project.
Your answer
![](https://koobas.hobune.stream/wayback/20220613110951im_/https://answers.unity.com/themes/thub/images/avi.jpg)