Unity Problem with Raycasting Masklayers or distance - c#

Im trying to make 2 types of enemies, melees and ranged, so im trying that both have a raycast to the player to know if they can see the player and are enought near, but I have two problems. The first one is that when I check the distance between the enemy and the player is always 0, and the second is that Raycast doesnt print when it should.
Let me explain, Im in front of the enemies and it prints that sees me, but other times not, in the same conditions, so i dont know what im missing.
Here is my code :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyMelee : EnemyBase {
public int rangoAttack;
RaycastHit hit;
int layerMask = 1 << 2;
void Update () {
perseguir();
attackMele();
}
void attackMele() {
if (Physics.Raycast(transform.position, player.transform.position, layerMask)){
print(hit.distance);
}
Debug.DrawLine(transform.position, player.transform.position, Color.red);
}
}
Enemies are on Layer 2
Pd: EnemyBase script just have movement to the player with nav.SetDestination (player.position);
Image of the enemy (cant upload images yet): https://ibb.co/eq7pMV

First problem occurs because you don't use hit in the code. So hit.distance = 0.
Second problem occurs because in Physics.Raycast(transform.position, player.transform.position, layerMask) you should set direction in 2nd argument (Not endpoint). You can calculate direction by this: Vector3 direction = player.transform.position - transform.position.
Try this code:
RaycastHit hit;
int layerMask = 1 << 2;
public float maxDistance;
void Update ()
{
attackMele();
}
void attackMele()
{
Vector3 direction = player.transform.position - transform.position;
if (Physics.Raycast(transform.position, direction, out hit, maxDistance, layerMask))
print(hit.distance);
Debug.DrawLine(transform.position, player.transform.position, Color.red);
}
I hope it helps you.

Related

How can I lock the rotation of a player in Unity?

I'm currently making a 2D game as a beginner and I made a spinning platform. But when it's rotating the player's rotation (z-axis) also changes because it's a child of the platform. I need this when I use moving platforms. Now I want to lock the z-axis of the rotation of the player. I already tried it in 3 different ways, but none of them seems to be working. Does anybody know how to do this?
These are the three ways I tried:
// 1
PlayerTrans.transform.Rotate(
PlayerTrans.transform.rotation.x,
PlayerTrans.transform.rotation.y,
0);
// 2
PlayerTrans.transform.Rotate(
PlayerTrans.transform.rotation.x,
PlayerTrans.transform.rotation.y,
0,
Space.Self);
// 3
PlayerTrans.transform.localRotation = Quaternion.Euler(new Vector3(
PlayerTrans.transform.localEulerAngles.x,
PlayerTrans.transform.localEulerAngles.y,
0f));
and this is, what my code looks like for staying on the moving platforms. I used raycasting for this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Raycasting : MonoBehaviour
{
// Start is called before the first frame update
Transform PlayerTrans;
public float RayCastRange = 3;
void Start()
{
PlayerTrans = transform.parent;
}
// Update is called once per frame
void Update()
{
RaycastHit2D PlattformCheck = Physics2D.Raycast(transform.position, -Vector2.up, RayCastRange);
if (PlattformCheck.collider != null)
{
if (PlattformCheck.collider.gameObject.tag == "Platform")
{
PlayerTrans.transform.SetParent(PlattformCheck.collider.gameObject.transform);
}
else
{
PlayerTrans.transform.SetParent(null);
}
}
else
{
PlayerTrans.transform.SetParent(null);
}
}
}
There are 2 ways that might help you:
Just freeze the rotation from the inspector:
you can use some LookAt function (there is one for 3D but you can look and find ones for 2D) and just look at the camera.
(if you cant find it let me know and I will add it)
You should raycast directly down and then apply velocities to both objects (un-child the player from the platforms). You could do something like this for the player:
public LayerMask mask; //set ‘mask’ to the mask of the
//platform in the Unity Editor.
public Vector3 velocity;
void Update()
{
RaycastHit hit;
if (Physics.Raycast(transform.position, -Vector3.up, out hit, 0.1f, mask))
//0.1f is the distance to the platform to be able to be moved by the platform.
{
velocity = hit.collider.gameObject.GetComponent<Platform>().velocity;
}
float h = Input.GetAxis(“Horizontal”);
//this one is for CharacterController:
cc.Move(velocity);
//this one is for rigidbody:
rb.velocity = velocity;
velocity = 0;
}
It takes the velocity from the ‘Platform’ script and moves the player based on it. Now we should add the platform script. Call it ‘Platform’.
public Vector3 velocity;
public Vector3 a; //a and b are the two points you want the platform to go between.
public Vector3 b;
public float period = 2f; //the amount of seconds per cycle.
float cycles;
void Update()
{
cycles = Time.time / period;
float amplitude = Mathf.Sin(Mathf.PI * 2f * cycles);
Vector3 location = Vector3.Lerp(a, b, amplitude);
velocity = transform.position - location;
transform.position = velocity;
}
This script interpolates between the point a and b, then it finds the velocity and applies it. The player takes this velocity and it moves the player. Comment if you found an error.

Instantiate from raycast without intersect

So I want to know how to instantiate a GameObject without intersection in Unity3D. As of now, the sphere instantiates intersected with the object that I hit with the raycast. I am using the location of hit.point, but would like to know if there is a way to spawn it on the collisions instead of the origin of the object. Here is my code for reference:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BallSpawn : MonoBehaviour
{
public int castLength = 100;
public GameObject spawnObject;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
//Input.GetMouseButton for infinite
if (Input.GetMouseButton(0))
{
SpawnBall();
}
}
public void SpawnBall()
{
RaycastHit hit;
Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.forward) * castLength, Color.green, Mathf.Infinity);
if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out hit, castLength))
{
Instantiate(spawnObject, hit.point, hit.transform.rotation);
}
}
}
As of now, the spheres clip into the ground and bounce out when they are spawned. I would like it for the spheres to be "placed" so to speak, so that they spawn without clipping.
You can try to replace hit.point with hit.point + hit.normal * ballRadius (of course you must know or be able to get what the ball radius is). But this will result with some spawn positions being off, especially if you hit a surface under small angle.
Better alternative is to replace ray cast with Physics.SphereCast (transform.position, sphereRadius, transform.forward, out hit, castDistance). This should give you good results but again you will still have to add the ball radius along the hit normal just like the raycast.

Is there a way to rotate an object that is a child of a parent with animator?

The animator make the object to rotate so the script I'm using with a raycast is not working.
Only if I disable the animator then when the raycast hit an item the head of the character will rotate look at the item.
but is there a way to make that the player head will rotate look at the item even if the animator is still working ?
The script that attach to the player :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Interactable : MonoBehaviour
{
public Transform objToRotateLookAT;
private bool raycastSucceed;
// Start is called before the first frame update
void Start()
{
}
void FixedUpdate()
{
int layerMask = 1 << 8;
RaycastHit hit;
// Does the ray intersect any objects excluding the player layer
if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out hit, Mathf.Infinity, layerMask))
{
if (!raycastSucceed)
Debug.Log("Did Hit");
raycastSucceed = true;
Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.forward) * hit.distance, Color.red);
Vector3 relativePos = hit.transform.position - objToRotateLookAT.position;
// the second argument, upwards, defaults to Vector3.up
Quaternion rotation = Quaternion.LookRotation(relativePos, Vector3.up);
objToRotateLookAT.rotation = rotation;
}
else
{
if (raycastSucceed)
Debug.Log("Did not Hit");
raycastSucceed = false;
Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.forward) * 1000, Color.yellow);
}
}
}
The player head will rotate facing the item detected only if the animator is disabled. Is there a way to keep the animator active and also to rotate the head facing the detected item ?
Well, you can't make that in Player's animator because you disabled it. But you can change its rotation in another game object. For example, you can put a HeadManager gameObject with an Animator inside. And whenever you want to make the head rotate, you can just make the Bool in animator of HeadManager.
If you have more than 1 object that you want to rotate their head, you can make this HeadManager child of that game object. And when you hit, you can just simply get it's children's animator and make the bool true.
https://docs.unity3d.com/ScriptReference/Component.GetComponentInChildren.html
You can check this to get the children's animator.

Unity3D - Raycast not hitting correct position

I'm trying to make a gun by shooting a ray from the centre of the camera which the gun is a child of, I also have a particle effect where the impact happens only, the impact happens in the wrong position.
I did Debug.DrawLine and saw that the origin of the ray was happening 0.8 units above the center of the camera, and it sometimes hits directly on the camera
Here is the gun script
using UnityEngine;
public class GunShoot : MonoBehaviour
{
public float gunDamage = 1f;
public float fireRate = .1f; // wait x seconds to fire again
public float weaponRange = 100f;
public float hitForce = 100f;
public Camera playerCam;
//public ParticleSystem muzzleFlash;
public GameObject impactEffect;
private float nextFire; // Holds the time for which the gun is able to fire again
void Update()
{
Shoot();
}
public void Shoot()
{
if (Input.GetButtonDown("Fire1") && Time.time > nextFire)
{
nextFire = Time.time + fireRate;
RaycastHit hit;
if (Physics.Raycast(playerCam.transform.position, playerCam.transform.forward, out hit, weaponRange)) // Center of the camera, directly forward, hat it hits and that infomation, the range of the weapon
{
Target target = hit.transform.GetComponent<Target>();
if (target != null)
{
target.TakeDamage(gunDamage);
}
GameObject impactGameObject = Instantiate(impactEffect, hit.point, Quaternion.LookRotation(hit.normal));
Destroy(impactGameObject, .15f);
}
}
}
}
I have been using a tutorial by Brackleys https://www.youtube.com/watch?v=THnivyG0Mvo but i followed it perfcetly (execpt chaning some variable names) and i cannot see where it is going wrong.
I cant just reduce the high of the initial ray as it sometimes maybe 1/10 times shoots from the right position
As you can see it clearly isn't shooting from the middle where the crosshair is
Any help would be great thanks!
Consider using Camera.ScreenPointToRay.
If you're always shooting from the center of the screen you could use Camera.ViewportPointToRay
Ray ray = Camera.main.ViewportPointToRay(new Vector2(0.5f, 0.5f));
if (Physics.Raycast(ray, out RaycastHit hit, weaponRange)) // handle hit

Attached script that uses RayCast to an empty game object and now it's not working, why?

I want to shoot a raycast out of the tip of enemies gun and see if it hits the player. To do this I created an empty game object placed inside of the gun in the hierachy and moved the empty game object which I called TipOfGun not I attached script to TipOfGun called Gun with rayCast but it does nothing as far as I'm concerned and after all the testing I've done. I can't figure out why raycast never hits anything. Below is my code and i'm also posting a picture of my hierarchy.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Gun : MonoBehaviour
{
private ParticleSystem muzzleFlash;
Vector3 tipOfGun = new Vector3(0.009f, 0.329f, 0.017f);
// Use this for initialization
void Start()
{
GameObject muzzleFlashObj = GameObject.Find("muzzleFlash");
muzzleFlash = muzzleFlashObj.GetComponent<ParticleSystem>();
}
public void ShootWeapon()
{
muzzleFlash.Play();
Ray ray = new Ray(transform.position, transform.forward);
RaycastHit hit;
if (Physics.SphereCast(ray, 0.75f, out hit))
{
Debug.Log("Name of component hit:" + hit.collider.gameObject.name);
GameObject hitObject = hit.transform.gameObject;
if (hitObject.GetComponent<PlayerController>())
{
muzzleFlash.Play();
}
else
muzzleFlash.Stop();
}
}
}
You are using Physics.Spherecast which isn't what you are looking for.
From your description I think you should use Physics.Raycast
Try something like this instead of Spherecast:
if (Physics.Raycast(transform.position, transform.forward, out hit))
Give it a try.
After breaking my head a few hours in between days I decided to see if I can see the actual Raycast to determine why it was not hitting my player. I should've thought of this way before for those of you that run into a similar problem you can always draw the actual ray and view it in the scene, with something similar to this.
Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.forward) * hit.distance, Color.yellow);
Debug.Log("Did Hit");

Categories