Problem with using Physics.Raycast to check if grounded - unity3d

I'm making a multiplayer FPS with Unity 2018 and I'm trying to detect if grounded using a raycast to see whether the player can jump or not.
I've written a function which should work based on multiple guides, but it returns seemingly random values whether the player is actually grounded or not.
My function:
bool IsGrounded()
{
RaycastHit hit;
if (Physics.Raycast(transform.position, -transform.up, out hit, 1f))
{
Debug.Log("Hit");
return true;
}
else
{
Debug.Log("Miss");
return false;
}
}

#SgtOddball I had a similar issue. I believe 1f is hitting your Player.
Add a layermask to exclude your player, make 1f Mathf.Infinity for now since I believe it is too small, and use
Debug.DrawRay(transform.position, -transform.up * 1f, Color.RED)
to see just how long 1f really is. I don't believe it is.

Related

2D Object Not Detecting When Hit by Raycast

I'm creating a top down 2D game, where the player has to break down trees. I made it so the player casts a ray toward the mouse, and when the ray hits a tree, it should lower the tree's health. I don't get any errors when I run the game or click, but it seems like the tree isn't detecting the hits.
void Update()
{
...
if (Input.GetMouseButtonDown(0))
{
RaycastHit2D hit = Physics2D.Raycast(playerRb.transform.position, mousePosition - playerRb.transform.position, 2.0f);
if (hit.collider != null)
{
if (hit.collider == GameObject.FindWithTag("Tree"))
{
hit.collider.GetComponent<TreeScript>().treeHealth--;
}
}
}
}
Still pretty new to coding and I'm teaching myself, so please make your answer easy to understand to help me learn.
Input.mousePosition is equal to the pixel your mouse is on. This is very different than the location your mouse is pointing at in the scene. To explain further, Input.mousePosition is where the mouse is. Think about it. If the camera was facing up, the mouse positon would be the same, but where they are clicking is different.
Instead of using Input.mousePosition, You should pass this into a function called Ray Camera.ScreenPointToRay();
You just input the mouse position and then use this new ray to do the raycast.
ANOTHER EXTREMELY IMPORTANT THING 1: Do not use Camera.main in Update(), as it uses a GetComponet call, which can cause perormance decreases. Store a reference of it in your script and use that.
Extremely important thing 2: I notice you are using GetComponent to change the tree's health. This is fine, but do not use GetComponent if you don't have to.
Like this:
Camera cam;
void Start()
{
cam = Camera.main; //it is fine to use this in start,
//because it is only being called once.
}
void Update()
{
...
if (Input.GetMouseButtonDown(0))
{
Ray ray = cam.ScreenPointToRay(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(ray);
...
}
}
You need to convert your mouse position from screen point to world point with Z value same as the other 2D objects.
Vector3 Worldpos=Camera.main.ScreenToWorldPoint(mousePos);
Also use a Debug.DrawRay to check the Raycast
Debug.DrawRay(ray.origin, ray.direction*10000f,Color.red);
Source

Raycasthit2d is not detecting any collisons

I've done some googling and can't figure out why this isn't working.
This is part of a dash ability that checks for collisions. it returns a bool so if true then I can dash and if false I cannot dash.
Here is my code.
All of the debugs are logging what they should be except no matter what it returns true.
private bool CanMove(GameObject parent, Vector3 dir, float dis)
{
RaycastHit2D rayCastHit = Physics2D.Raycast(parent.GetComponent<Transform>().position, dir, dis, Enemies);
Debug.Log(parent.GetComponent<Transform>().position);
Debug.Log(dir);
Debug.Log(dis);
if (rayCastHit.collider == null)
{
Debug.Log("true");
return true;
}
else
{
Debug.Log("false");
return false;
}
}
Here is a picture of me testing. This shows the log after I've dashed through a wall, which I shouldn't have been able to dash through.
https://i.stack.imgur.com/PGc4E.png
Issue was with the large collider colliding with a rigidbody2d component. I've since removed the large collider entirely because it was a bad solution to my problem to begin with.

How to create a Raycast that will allow a turret to see if a player is behind a wall?

so, basically, I have created a pretty simple turret script that basically just smoothly aims at the player, so long as the player is within a certain amount of range. The problem I am having, is that the Raycast I wrote that actually checks if the 'bullet' (which is nothing - it's just a raycast), would hit the target. This means that even if the player hides behind a wall, the turret can still shoot him.
My current raycast script allows the raycast to go straight through the wall, and since I am new to Unity, I have no idea how to make it check if the first object it hits is the player, so that it cannot go through walls.
Here is my current raycast script:
void Shoot()
{
//I think the problem is here - I want the raycast to return false if it hits a wall - which has the layer "ground", and true if it hits the player. Problem is, I need to make the turret return to resting position when the player is behind a wall.
//To do this, I can just set inRange = true; But I need to be able to determine when the player is behind a wall.
LayerMask layerMask = LayerMask.GetMask("Player");
if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out RaycastHit hit, Mathf.Infinity, layerMask))
{
//This determines how much damage will the player take.
int damage = Random.Range(1, 5);
hit.collider.gameObject.GetComponent<playerMovement>().Shot(damage);
//I personally THINK this means that it only triggers collisions with the player, which is why it is not working.
// The player has layer "Player", and tag "Player", so if anyone who wants to help can figure out how to make it stop when it hits anything - and then only return true if it hit the player (meaning the player is not behind walls).
}
}
If you want to check if there is anything between the player and the Raycast, then simply remove the Layermask
Change this:
LayerMask layerMask = LayerMask.GetMask("Player");
if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out RaycastHit hit, Mathf.Infinity, layerMask))
To this:
Ray ray = new Ray(transform.position, transform.TransformDirection(Vector3.forward));
if (Physics.Raycast(ray, out RaycastHit hit) {..}
You want to
remove the check for the layer in order to hit everything with the raycast
then you can use TryGetComponent to check whether the hit object has such component attached or not
and in general instead of
transform.TransformDirection(Vector3.forward)
simply use transform.forward ;)
So something like
void Shoot()
{
if (Physics.Raycast(transform.position, transform.forward, out var hit))
{
// Without the need for any tag or layer check
// Simply check if the object you hit has a playerMovement component
// GetComponent was improved a lot lately and now uses hashes
// it's not that performance intense anymore and almost as fast as CompareTag
if(hit.gameObject.TryGetComponent<playerMovement>(out var movement)
{
int damage = Random.Range(1, 5);
movement.Shot(damage);
}
}
}
All you'd need to do is cast from the turret to the player and detect what the raycast has hit. Your current code is setting a mask to only be on the player, so it will never hit a wall. You can change your code to something like this:
private LayerMask layerMask = (1 << LayerMask.NameToLayer("Player") | (1 << LayerMask.NameToLayer("ground")));
void Update () {
if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out RaycastHit hit, Mathf.Infinity, layerMask))
{
if(hit.collider.gameObject.layer == LayerMask.NameToLayer("Player"))
{
// you can shoot as you see the player
}
else
{
// you hit the ground - player is behind a wall
}
}
}

OnTrigger Events Work With Delay

I've got a bullet script with a particle system and a decal.
I think that it has something to do with these events not being able to fire in time or with fps in update. Not sure yet.
So, it's being late.
The ellow points are where the particles start to play. They should be right on these wooden walls. There should be three particles working and three bullet holes, kinda bullet penetrating one wall and getting destroyed on the second one.
THE QUESTION IS HOW TO MAKE IT WORK NORMAL, SO THAT THE TRIGGERS WORK WHEN NEEDED AS WELL AS THE PARTICLES AND THE DECALS? Maybe there's a way to excellerate the code to work on time? Or maybe there's another problem with that?
The screenshot:
The Code:
public class BulletScript : MonoBehaviour {
public bool isThrough = true;
public float BulletSpeed = 100;
public float CurrentDamage;
public float EnterLuft = -0.005f;
public float ExitLuft = 0.05f;
public GameObject woodParticle;
private ContactPoint CollisionPoint;
public GameObject BulletMarkPref;
Rigidbody bullet;
private void Start()
{
bullet = this.GetComponent<Rigidbody>();
}
void FixedUpdate () {
bullet.velocity = Vector3.forward * BulletSpeed;
//this.transform.Translate(Vector3.forward * BulletSpeed * Time.deltaTime);
}
private void OnTriggerEnter(Collider other)
{
Transform hitPoint = this.transform;
LevelObject.LvlObjectType objectType = other.gameObject.GetComponent<LevelObject>().objType;
if(objectType == LevelObject.LvlObjectType.obstacle)
{
if (isThrough)
{
Instantiate(woodParticle, hitPoint.localPosition, Quaternion.LookRotation(-hitPoint.forward)).GetComponent<ParticleSystem>().Play();
LeaveBulletMark(this.transform, true);
}
else
{
Instantiate(woodParticle, hitPoint.localPosition, Quaternion.LookRotation(-hitPoint.forward)).GetComponent<ParticleSystem>().Play();
LeaveBulletMark(hitPoint, true);
Destroy(this.gameObject);
}
}
else if(objectType == LevelObject.LvlObjectType.obstacle)
{
Destroy(this.gameObject);
}
else if(objectType == LevelObject.LvlObjectType.wall)
{
LeaveBulletMark(hitPoint, true);
Destroy(this.gameObject);
}
}
private void OnTriggerExit(Collider other)
{
Transform hitPoint = this.transform;
Instantiate(woodParticle, hitPoint.localPosition, hitPoint.rotation).GetComponent<ParticleSystem>().Play();
LeaveBulletMark(hitPoint, false);
}
void LeaveBulletMark(Transform hitPoint, bool ifEnter)
{
GameObject TemporaryBulletMarkHandler;
TemporaryBulletMarkHandler = Instantiate(BulletMarkPref, hitPoint.localPosition, Quaternion.LookRotation(ifEnter ? hitPoint.forward : CollisionPoint.normal)) as GameObject;
isThrough = false;
TemporaryBulletMarkHandler.transform.Translate(hitPoint.forward * (ifEnter ? 0.005f : -0.005f));
}
}
I don't think your problem is something simple with the code. There is an inherent issue with calculating fast moving objects like bullets with true physics calculations especially if they are small. Often between physics updates, they pass through wall colliders completely without registering.
You have to think of it like this to see the problem. The bullet isn't tracked continuously along its trajectory. It has a starting location, a formula for its movement and it calculates a new location at each physics update. You could fire a bullet straight at a wall, and in one update the bullet would be several meters in front of the wall, and in the next, it would be several meters behind the wall without ever triggering a collision. This is why so many game use ray tracing to calculate bullet trajectories. The bullet movement isn't perfectly accurate, especially for long shots, but obstructions to the bullet path are registered.
By default unity's Physics Engine runs at 50 frames per second. A modern bullet travels between 1200 and 1700 m/s. That gives you a distance between 24 and 34 meters traveled between frames. Even a small object falling at terminal velocity (54 m/s) might pass through a collider unnoticed. If you made a 1-meter thick box collider, you would likely register a falling object but not a bullet.
I think you could do some clever combination of ray tracing and bullet physics to get the best of both worlds. Maybe you could ray trace from the bullet at each fixed update or there may be some better technique already invented for this exact situation that I don't know about.

Physics.Raycast not working with Google Cardboard / Google VR

I have a Physics Raycaster attached to the Camera. The Pointer Click Event Trigger is working correctly. However I need to do it from the source code. These are my attempts:
private void SetOnPushButtonFireManager(){
cardboard.OnTrigger += () => {
Debug.Log("Button triggered!");
RaycastHit hit;
// if(Physics.Raycast(headGameObject.GetComponent<GvrHead>().Gaze, out hit, Mathf.Infinity)){
if(Physics.Raycast(cameraGameObject.transform.position, cameraGameObject.transform.forward, out hit, Mathf.Infinity)){
Debug.Log("Collision detected!");
}
};
}
"Button triggered!" is shown in the Console. Unfortunately "Collision detected!" is not. However the Pointer Click Event Trigger is working correctly (the component attached in the inspector). How can I know what is going on? Why isn't it working?
UPDATE: I have answered this answer here: http://answers.unity3d.com/answers/1200449/view.html
(stackoverflow does not allow me to delete this question)
Here's some code I've been using to fire a ray from the camera. I don't have Google Cardboard, this was setup for a camera and a mouse pointer.
// Fire ray from camera
float rayLength = 2f
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
// If ray hits object within length
if (Physics.Raycast(ray, out hit, rayLength))
{
Debug.Log("Collision detected!:);
}
It didn't work for me either, in the end, I forgot to put the "GvrPointerPhysicsRaycaster" class in the camera. Inspector Image
Once added, it worked perfectly.
void Update()
{
RaycastHit hit;
if (Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out hit, Mathf.Infinity))
{
if (activeSelected == null)
{
if (hit.collider.tag == "Plane")
activeSelected = Instantiate(mainApp.mainModel.preafabSelect, hit.point, Quaternion.LookRotation(hit.normal));
} else
{
activeSelected.transform.position = hit.point;
activeSelected.transform.rotation = Quaternion.LookRotation(hit.normal);
}
}
}