I have an object with circle collider 2d, and an object with box collider 2d. how do i detect when the circlecollider hits the top edge of the box collider. assuming none objects have any rotation. i want to do this in code C#
OnCollisionEnter triggers when something collides with the object containing this script, used like this:
void OnCollisionEnter(Collider collider)
{
foreach(CollisionPoint contact in collider.contacts)
{
//Do something
}
}
The above will give you a list of contact points for the collision, via which you should be able to determine where the collision occurred. An alternative method if you only need to detect collisions at a specified location, you could place an invisible child object within your cube, with a collider at the spot you want.
Edit:
Since you mentioned raycasts, there's 2 ways I can think of that these could be implemented. The first is to fire it upwards from the cube, but this has the issue of the ray firing from just 1 point, meaning some collisions might be missed (depending on the size of the cube & sphere).
The second method that pops to mind is to fire the ray parallel to the cube. This might sound a bit unorthodox, and I haven't tested it, but in theory it should work. Stick it in your cube:
void Update
{
Vector3 start = this.transform.position;
Vector3 end= this.transform.position;
//This attempts to place the start & end point just above the cube
//This of course assumes the cube isn't rolling around. If that's the case
//then these calculations get quite a bit more complicated
//Additionally the 0.01 might need adjusting if it's too high up off the cube
start.y += this.renderer.bounds.y/2 + 0.01f;
end.y += this.renderer.bounds.y/2 + 0.01f;
start.x -= this.renderer.bounds.x/2;
end.x += this.renderer.bounds.x/2;
Ray ray = new Ray(start, end);
RaycastHit hit;
if(Physics.Raycast(ray, out hit, start.x-end.x) && hit.name == "mySphere")
{
//Theoretically, the sphere hit the top of the box!
}
}
Related
I'm trying to make a simple FPS game in Unity3d where a character cannot fall off the platform unless they jump off of it, walking off should be impossible.
I made a script for objects that are on a moving platform:
public GameObject Player;
private void OnTriggerEnter(Collider other)
{
if (other.gameObject == Player)
{
Player.transform.parent = transform;
}
}
private void OnTriggerExit(Collider other)
{
if (other.gameObject == Player)
{
Player.transform.parent = null;
}
}
And the only way I came up with to solve this problem is to create a short, invisible box collider working as a threshold, but adding it to every edge of every walking space would be a nightmare. Also I can't use nav mesh for it.
Raycasting just in front of the player pointing down and seeing if it hits the level would be one option, however it's very expensive to run this a lot.
If your level is square (other shapes will work but will require some maths), you can take note of the top left and bottom right points as your boundary points and check if your players position + walking speed per frame would be outside this boundary square. If it is, deny the move.
E.g
if((transform.position + transform.forward * walkingSpeed * time.deltatime).x > maxX || < minX || .y > maxY || .y << minY)
//Deny the move
In the same way that you use colliders to detect the ground to allow / disallow jumping, you can also use colliders to detect edges of platforms.
Add a small collider to each corner or midpoint of each side of the bottom of your player object. The player can only move in directionA if the colliders on sideA of the player are in contact with the ground. This means that as you approach a ledge, the nearest side to the ledge will lose contact with the ground, therefore preventing any more movement in that direction.
If player is jumping, then allow movement in all directions regardless of collider contact.
You will have to play around with the position of these colliders and which directions you allow movement, but this seems like a simple yet effective approach to me.
Create a prefab for the edges, everywhere there is an edge place the prefab so that the prefab is really the edge. This will ensure that the code that works is always present on an edge.
I am making a bot for a tank game and right now I am trying to make him evade Obstacles. For that I am using RayCastHit, the problem is that my RayCastHit seams to ignore obstacles. So far I have
public float sensor_length = 10f;
shows how long the sensor is allowed to be
public float car_length = -5f;
the tank is spun with 180 degrees, and this causes the sensor to come from front.
In a Method I have:
RaycastHit hit;
Vector3 sensorStartpos = transform.position;
sensorStartpos.z += car_length;
if(Physics.Raycast(sensorStartpos,transform.forward,out hit,sensor_length))
{ }
Debug.DrawLine(sensorStartpos, hit.transform.position);
So I am getting my object transform point, then locate the front of it and it should fire a RayCast. Here comes the problem, as shown I didnt identify hit so its value is null and in the if statement I should fire one check to the next obstacle, but instead it fires one to point (0,0,0) (I am guessing because hit = null
How do I cause it to hit an obstacle instead?
(The debug line on the bottom causes the Ray Cast to be visualized)
I have a bullet that is fired with a Impuls on the rigidbody.
Then, each frame i do a raycast forward with the speed of the bullet, which sometimes does, and sometimes doesn't find an enemy.
When i skip through the game frame by frame, i can clearly see my debug-raycast inside the (boc)collider of the enemy, but it still won't find it.
Im pretty sure it doesn't just pass the enemy, in the editor i can clearly see the green raycast inside the collider.
Any suggestions? I also tried with a linecast, which i found on here, but that gives the same result. (the line is on the exact same position and also draws the debug-line inside the collider. The layers are also correct, as i said, sometimes it will, and sometimes it wont find the target...
void Update()
{
//get direction and distance
Vector3 direction = _rigidBody.velocity.normalized;
float distance = (_rigidBody.velocity.magnitude * Time.deltaTime);
//raycast for targets
RaycastHit raycast;
if (Physics.Raycast(transform.position, direction, out raycast, distance, HitLayerMask))
{
Debug.DrawRay(transform.position, direction, Color.red);
}
else
{
Debug.DrawRay(transform.position, direction, Color.green);
}
}
You can see the tiny debug ray, aswell als the collider from side-view. It also it almost right in the middle from the front-view.
I'm thinking it might be because the start and end of the raycast are inside the boxcollider?
the rigidbody is moved by
//Speed = 500 in this case, but lowering doesn't change anything
rigidBody.AddRelativeForce(Vector3.forward * Speed, ForceMode.Impulse);
UPDATE:
After some more debugging and testing, i found that it happens because you won't get a hit from inside a collider.
Here's what happend:
bullet is outside target collider, but raycast is to short to find it.
bullet moves forward, enemy also moves forward (closing in on eachother). Bullet is now inside the collider
raycast won't find enemy because thats just how raycast work
What i could do, is make the distance of the raycast further, but also not so far away that it would result in weird hits that would graphically look weird.
i thought that using
float distance = (_rigidBody.velocity.magnitude * Time.deltaTime);
would be enough (since thats the distance the bullet traveled since last frame, but because the enemy also moves, the above can happen. Well, it would be enough if the enemy wouldn't move :/
One possible solution is to go to Project Settings -> Script execution order and put the bullet's MonoBehavior after Default Time. That way everything else has already finished moving before you do the ray cast. A hacky solution but should work.
I'm trying to detect the ground ahead of a cube that doens't have boxcollider or rigid body. I can detect it ok but the distance never changes. I can use very big number or very small ones that it still detects the ground at the same distance.
The debug lines are working fine and nothing is detected before the ground. Even trying raycast without distance keeps the detection at the same distance.
I tried some other variations of the method Raycast with the same results.
Here is my script:
Ray ray = new Ray(transform.position, transform.forward);
RaycastHit hitInfo;
Debug.DrawRay(pos, transform.forward * detectDistance, Color.green);
if (Physics.Raycast(ray,out hitInfo, detectDistance)) {
Debug.Log(hitInfo.transform.name);
Debug.DrawRay(pos, transform.forward * detectDistance, Color.red);
}
If your main goal is to calculate the distance between two GameObjects (cube and ground), the use of Raycast is not a must. You can follow this other approach:
Vector3 dist = Vector.distance(cube.transform.position, ground.transform.position);
Debug.Log(string.Format("Distance between {0} and {1} is: {2}", cube, ground, dist));
However if you want to keep with the Raycast, without having all the information about how is your scene and how are the gameObjects located, I can only recommend you to try the following things:
1- Calculate the direction of the Ray like this:
Vector3 direction = ( cube.transform.position - ground.transform.position ).normalized;
Ray ray = new Ray( cube.transform.position, direction );
2- Calculate the distance from hit:
if (Physics.Raycast(downRay, out hit)) {
float distance = hit.distance;
}
3- And just in case calculate the distance from void FixedUpdate()
The problem was the other terrain chunks wasn't generating the collider mesh till you get really close to it.
I did find a way to generate it far away.
I have a Light_Spell script attached to a magic wand which is parented to a Razer Hydra hand object. The Light_Spell takes a prefab of a Light which is projected out of it when a button is pressed.
However the light is just moving up, no matter what way I rotate the hand object, it always goes up. I had it working but I changed some code around and can't remember how I got it working in the first place.
Here is the code I have so far:
//What happens when bumper is pressed
if (isSelectedSpell && SixenseInput.Controllers [0].GetButtonDown (SixenseButtons.BUMPER) && triggerIsPressed == false) {
Rigidbody instantiateProjectile = Instantiate(projectile, transform.position, transform.rotation) as Rigidbody;
instantiateProjectile.position += Vector3.down * 20.0F;
}
I have tried setting Vector3 to up and forward and a whole set of different things. Any ideas on what I should do to make it match the rotation of where the hand is pointing and stuff?
Thanks
Consider using:
instantiateProjectile.position += -instantiateProjectile.transform.up * 20.0f;
Explanation:
Vector3.down is not relative to the transform's rotation, it is a 'down' in World space, that is to say it will always be going down according to the cardinal axes.
transform.up is relative to that transform's rotation. If the projectile is rotated, the axes used to obtain "up" are rotated too. We must use an inverted transform.up instead of transform.down because no transform.down exists.