I have a character controller which moves along the z-axis with a constant speed. I'd like to know the floor name under the character controller. The Character controller never collides with the floor. It's a parallel movement. I used a Raycast to find the floor in C# using:
myray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(myray, myhit, 1000)) {
Debug.DrawLine (ray.origin, hit.point);
print(myhit.collider.name);
}
This gives an error. Is there a better solution for this?
It's hard to tell what your issue is, but attaching this behaviour to your character-controlled object will get the name of the first object the raycast hits.
I'm using an inverted layer mask to ignore the "Player" layer, which I set the character-controlled object to. This is so the raycast doesn't hit the object before the floor.
using UnityEngine;
using System.Collections;
public class GetFloorName : MonoBehaviour
{
public string NameOfRaycastHitObject;
void Update ()
{
RaycastHit hitInfo;
int layerMask = ~(1 << LayerMask.NameToLayer("Player"));
float distance = 100f;
if (Physics.Raycast(transform.position, Vector3.down, out hitInfo, distance, layerMask))
{
NameOfRaycastHitObject = hitInfo.collider.name;
}
}
}
Related
Like the image above, I want to place an object so that it faces away from the surface( I am using graphics instancing to create grass). I assume this will have to do something with the surface normals/ raycasting, but I can not figure out how to do it. I'm using unity and c# so answers relating to that would be great.
I haven't really been able to get off my feet with this problem, but I've tried rotating it so that it faces up always, but that results in a lot of clipping and weird behavior.
Complicated problem of which Unity already has a solution. Here is a script to automatically align it to the normal. I've also added a LayerMask option so you only hit the correct layer on your check as well as a max height value. Remember to set both from the Inspector.
public class NormalRotation : MonoBehaviour
{
public float maxHeight = 2f;
public LayerMask layer;
void Update() => RotateTransformToNormal();
void RotateTransformToNormal() =>
transform.rotation = Quaternion.FromToRotation(transform.up, GetNormal()) * transform.rotation;
Vector3 GetNormal()
{
// Raycast down from the transform
Ray ray = new Ray(transform.position, Vector3.down);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, maxHeight, layer))
{
return hit.normal;
}
return transform.up;
}
}
I'm currently trying to have a raycast detect the player caracter to have an event happen when a specific key is pressed here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class action: MonoBehaviour
{
public float dist;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
RaycastHit2D down = Physics2D.Raycast(transform.position, -Vector2.up, dist);
Debug.Log(transform.position);
if (Input.GetKeyDown(KeyCode.Z) == true && down.collider != null)
{
Debug.Log("hi");
}
}
}
I'm basicly trying to make a small raycast,which is why I place a distance instead of letting it go infinitely, and have it so if the raycast is triggered and the player presses z the event happens(which for now is the debug console), but all it does now is triggers whenever I press z no matter where the player caracter is. I tried drawing the raycast but I can't seem to make it work.
I think the reason for that is that the raycast is hitting the object containning the script it self and so the collider is allways non null try adding a LayerMask that differs from the GameObject's Layer
so it's something like this :
RaycastHit2D down = Physics2D.Raycast(transform.position, -Vector2.up,
dist , 1 << /*The Target's Layer*/);
You can find the layer in the up left corner of your inspector when you click on a GameObject
You have not provided a LayerMask on the down. The Raycast must be colliding with the player's Collider. In case you don't know what LayerMask is.
LayerMask can be used to detect Raycast that collides with only the objects with that layer on it.
The ayer Dropdown, on each GameObject, refers to the layer of the object as shown:
Head to the Unity Documentation for LayerMask for more details.
If you want make raycast when press Z will be good to do it in time press:
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Z)){
RaycastDown()
}
}
private void RaycastDown()
{
Debug.Log("Player position: " + transform.position);
RaycastHit2D hit = Physics2D.Raycast(transform.position,
Vector2.down, dist);
if(hit.collider != null){
Debug.Log($"Hit object: {hit.transform.name}" );
}
}
And about issue, make sure that hit object has a collider or collider is active.
Possibly problem in raycast direction. To check it, use Debug.DrawRay, it`s help you to visualize a ray which you draw
i am working on an enemy for my game that follows you until it doesnt see you anymore.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class pathfindingPlayer : MonoBehaviour
{
RaycastHit hit;
NavMeshAgent _navMeshAgent;
void Awake() => _navMeshAgent = GetComponent<NavMeshAgent>();
public bool seen;
public float noticeDistance = 7f;
void Update()
{
Debug.DrawRay(transform.position, transform.forward * noticeDistance, Color.red);
Ray PlayerRay = new Ray(transform.position, Vector3.back);
if(Physics.Raycast(PlayerRay, out RaycastHit hitInfo, noticeDistance))
{
if (hitInfo.collider.CompareTag("Player"))
{
Vector3 SeenPlayer = hitInfo.point;
_navMeshAgent.SetDestination(SeenPlayer);
}
}
}
}
Now the problem is that there is only one Raycast being shot out. Therefore the enemy only runs in one direction. Is there a way to add multiple raycasts to this or do i need to rewrite the code? Thanks in advance
You can make a function that makes raycasts and call it every x seconds, but for what you want to achieve i would try putting a circle collider on the enemy with the radius of how far the enemy can see and make sure to set the collider as trigger, then make it go towards the player if the player triggers the collider
NavmeshAgent player not parallel to slope of hill when moving over hill. On plane surface its going smoothly.
See Video
Below Image properties of navMesh and player
https://ibb.co/fijmoV
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class SampleAgentScript : MonoBehaviour {
public Transform target ;
NavMeshAgent agent;
// private static bool start1=false , start2=false, start3;
// Use this for initialization
void Start()
{
agent = GetComponent<NavMeshAgent>();
}
void Update()
{
//if white button click moves to targer-1
agent.SetDestination(target.position);
}
}
I am not sure if NavmeshAgent is supposed to do that for you. This looks like something you're supposed to do manually.
You can correct the rotation of the character to match the slope by performing a raycast downwards and obtaining the normal of the hit point. After obtaining the normal of the hit point, you can then calculate the new rotation with that normal hit point. There are many ways to do that calculation but using Quaternion.FromToRotation and lerping the rotation with Quaternion.Lerp seems to work best.
Finally, make sure to the raycast is only done to Objects you considered as a "Hill" or "Ground". You can do this with the bitwise operation on the layer the "Hill" or "Ground" objects are placed on. The example below assumes that the Objects you consider as "Hill" or "Ground" are on a layer called "Hill".
//Reference of the moving GameObject that will be corrected
public GameObject movingObject;
//Offset postion from where the raycast is cast from
public Vector3 originOffset;
public float maxRayDist = 100f;
//The speed to apply the corrected slope angle
public float slopeRotChangeSpeed = 10f;
void Update()
{
//Get the object's position
Transform objTrans = movingObject.transform;
Vector3 origin = objTrans.position;
//Only register raycast consided as Hill(Can be any layer name)
int hillLayerIndex = LayerMask.NameToLayer("Hill");
//Calculate layermask to Raycast to.
int layerMask = (1 << hillLayerIndex);
RaycastHit slopeHit;
//Perform raycast from the object's position downwards
if (Physics.Raycast(origin + originOffset, Vector3.down, out slopeHit, maxRayDist, layerMask))
{
//Drawline to show the hit point
Debug.DrawLine(origin + originOffset, slopeHit.point, Color.red);
//Get slope angle from the raycast hit normal then calcuate new pos of the object
Quaternion newRot = Quaternion.FromToRotation(objTrans.up, slopeHit.normal)
* objTrans.rotation;
//Apply the rotation
objTrans.rotation = Quaternion.Lerp(objTrans.rotation, newRot,
Time.deltaTime * slopeRotChangeSpeed);
}
}
I am trying to cast a ray from inside source to Sphere.
my main camera position (0,0,0)
Sphere position (0,0,0) radius : 300
I want to know hit.position and hit.collider.gameobject
I am trying this below tutorial.
http://answers.unity3d.com/questions/129715/collision-detection-if-raycast-source-is-inside-a.html
Even if I tried tutorial, I can not see desirable result from console window.
(no Debug.Log result in my console window)
What should I have to do?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EyeTrackingPoint : MonoBehaviour
{
public float sphereRadius = 300; // position(0,0,0) radius 300
public GameObject screen3D; // sphere
public void Update()
{
Camera cam = Camera.main; // position(0,0,0)
RaycastHit hit;
Ray ray = new Ray(cam.transform.position,cam.transform.rotation * Vector3.forward * sphereRadius );
ray.direction = -ray.direction;
if (Physics.Raycast(ray,out hit)&&hit.collider.gameObject.Equals(screen3D))
{
Debug.Log(hit.point);
}
}
}
Thank you for reading.
Raycast in unity has to be conform to these things; Use a worldpoint from where the ray should originate. Use a direction for that ray. And u need to specifiy in which layer it is supposed to check. On top of that only objects with colliders can be hit, even if the gameobject is in the correct layer but doesn't have a active collider nothing will happen. Example ;
{
RaycastHit hit = Physics.Raycast(start, direction, 1000f, 1<<10);
}
The information of a successful raycast is saved in a RaycastHit;
The 1000f is a float value that limits the range of the raycast That way u can control how far it looks for an object.
If u do not specify the layermask in the raycast it will return the first object hit with any kind of active collider regardless in which layer it is.
Raycasts from inside colliders do NOT generate collisions.
if (Physics.Raycast(Vector3.zero, Vector3.up, 100))
Debug.Log("HIT");
"Hit" will never be written in console if a sphere is around the 0,0,0 world origin. When you move the sphere out , over and away from the origin, you will see it printed.
Those are impact in backfaces. You can enable it, though, enabling the checkbox in the Physics settings. See the documentation on this parameter on c# too: https://docs.unity3d.com/ScriptReference/Physics-queriesHitBackfaces.html