Raycasting in unity jumping to a wrong position - c#

I am having a problem with Raycasting. All I want to do is always know the position of my cursor in world space and it works, but only if the cursor is moving. when the cursor is not moving it jumps to a random point around 4 units down on the x and z-axis.
public class CameraMovementRay : MonoBehaviour
{
public Camera playerCam;
Ray cursorRay;
Vector3 playerPos;
public RaycastHit cursorHit;
public LayerMask clickPlain;
public bool cursorHittingFloor;
// Update is called once per frame
void Update()
{
cursorRay = playerCam.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(cursorRay, out cursorHit, 100f, clickPlain))
{
print(cursorHit.point);
Debug.DrawLine(cursorRay.origin, cursorHit.point, Color.red);
cursorHittingFloor = true;
}
else
{
Debug.LogError("Not on the grund");
cursorHittingFloor = false;
}
}

That wasn't working out but I did find code that does
``
public class LookAtMouse : MonoBehaviour
{
public Camera playerCamera;
Plane movementPlane = new Plane(Vector3.up, 0f);
Vector3 lookPoint;
Ray CursorRay;
// Update is called once per frame
void Update()
{
CursorRay = playerCamera.ScreenPointToRay(Input.mousePosition);
float enter = 0.0f;
movementPlane.Raycast(CursorRay, out enter);
lookPoint = CursorRay.GetPoint(enter);
print(lookPoint);
Debug.DrawLine(CursorRay.origin, lookPoint);
transform.LookAt(lookPoint);
}
}
``

Have you tried using Camera.ScreenToWorldPoint instead of Camera.ScreenPointToRay? I think it might work better for your purpose because it takes a Vector2 (MousePosition) in pixels and converts it conveniently to World Space Point. The Unity documentation to what I'm referring to is: https://docs.unity3d.com/ScriptReference/Camera.ScreenToWorldPoint.html
Let me know how it works out

Related

In unity 2D after applying force to a rigid body how do I make it rotate to face the direction of travel

new to all this. I've tried following a few examples i've found on here but none seem to work. The best I have right now is
rb.transform.up = rb.GetComponent<Rigidbody2D>().velocity.normalized;
but this makes the rigid body rotate immediately to the new direction of travel. is there a way to make it so it rotates slower rather than jumping in one frame to the new direction of travel?
Any help would be appreciated :)
here is the code ive used to apply the force, if that matters? i got it from a tutorial to apply force based on dragging the mouse
public class DragNShoot : MonoBehaviour
{
public float power = 10f;
public Rigidbody2D rb;
public Vector2 minPower;
public Vector2 maxPower;
public TrajectoryLine tl;
Camera cam;
Vector2 force;
Vector3 startPoint;
Vector3 endPoint;
public void Start()
{
cam = Camera.main;
tl = GetComponent<TrajectoryLine>();
}
public void Update()
{
if (Input.GetMouseButtonDown(0))
{
startPoint = cam.ScreenToWorldPoint(Input.mousePosition);
startPoint.z = 15;
}
if (Input.GetMouseButton(0))
{
Vector3 currentPoint = cam.ScreenToWorldPoint(Input.mousePosition);
currentPoint.z = 15;
tl.RenderLine(startPoint, currentPoint);
}
if (Input.GetMouseButtonUp(0))
{
endPoint = cam.ScreenToWorldPoint(Input.mousePosition);
endPoint.z = 15;
force = new Vector2(Mathf.Clamp(startPoint.x - endPoint.x, minPower.x, maxPower.x), Mathf.Clamp(startPoint.y - endPoint.y, minPower.y, maxPower.y));
rb.AddForce(force * power, ForceMode2D.Impulse);
tl.EndLine();
}
}
}
and here is script for the rotation
public class FaceDirectionOfTravel : MonoBehaviour
{
public Rigidbody2D rb;
// Update is called once per frame
void Update()
{
rb.transform.up = rb.GetComponent<Rigidbody2D>().velocity.normalized;
}
}
As you can see, I have just taken the velocity and applied that to the rotation, I guess this just immediatly changes it to match, but I want it to visibly rotate to match the rotation. I have tried some examples I have seen on here for Slerp but that only seemed to leave it in free rotation.. I must be missing something really obvious so thought I would ask on here. Thanks.
EDIT:
So I've kinda worked out a way to get it to work by creating another object on top of the object i wish to rotate and use Slerp to rotate the object on top to slowly rotate to the same as the original object which has to snap immediatly due to force applied the code is simply
public class RotateSprite : MonoBehaviour
{
[SerializeField] private Rigidbody2D rbOfTarget;
[SerializeField] private Rigidbody2D rb;
private void Start()
{
}
// Update is called once per frame
void Update()
{
rb.transform.position = rbOfTarget.transform.position;
rb.transform.rotation = Quaternion.Slerp(rb.transform.rotation, rbOfTarget.transform.rotation, 30* Time.deltaTime);
}
}
if anyone knows a better solution do let me know. Thanks.
Is your game in 3D or 2D? you keep saying it's 2D but the tag says it is 3D and if 2D you wouldn't need a Z position. and if it is in 3D you would have to change the rigidbody2D to just rigidbody.

Raycast goes backwards but the i code it to go forward

I try my best but my raycast still goes backwards every time - please I need help
Here's my code - basically the code shoots a raycast forward button to detected an enemy but instead the raycast goes the opposite way.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class milkscript: MonoBehaviour
{
NavMeshAgent Agent;
public Transform Point;
public float raydistance = 40f;
public float enemyview = 5f;
// Start is called before the first frame update
void Start()
{
Agent = GetComponent<NavMeshAgent>();
}
// Update is called once per frame
void Update()
{
RaycastHit Hit;
if(Physics.Raycast(Point.position,Point.position + Point.forward, out Hit, raydistance))
{
Debug.DrawRay(Point.position, Hit.transform.forward, Color.red);
Debug.Log(Hit.transform.name);
if(Hit.transform.tag == "chcolatemilk")
{
ChasePlayer(Hit.transform);
}
}
}
public void ChasePlayer(Transform target)
{
Agent.SetDestination(target.position);
transform.LookAt(target.position);
}
}
I think this is a combination of two issues
As mentioned your
Debug.DrawRay(Point.position, Hit.transform.forward, Color.red);
draws the ray in direction of Hit.transform.forward which is not the original direction you shoot your Raycast in
As a direction or the Raycast you are passing in
Point.position + Point.forward
which rather is a position.
You want to pass in only Point.forward as a direction
So it should rather be
void Update()
{
if(Physics.Raycast(Point.position, Point.forward, out var Hit, raydistance))
{
Debug.DrawLine(Point.position, Hit.transform.position, Color.red);
// TODO: remove this later! Logging every frame is quite expensive!
Debug.Log(Hit.transform.name);
// prefer "CompareTag" over "=="! It is a) slightly faster and b)
// instead of failing silently throws an error for typos and non-existent tags => better debugging live
if(Hit.transform.CompareTag("chcolatemilk"))
{
ChasePlayer(Hit.transform);
}
}
Debug.DrawRay(Point.position, Point.forward, Color.green);
}

Unity3D: How can i make my player go where i clicked with the mouse, without nav mesh agent?

I want to move my player around in my level without a NavMesh Agent.
I was thinking something about raycasting, but i have tried everything and even looked up videos and searched on google about it, can't seem to find anything that works
Plz help!
you can use this for moving to mouseclick position.
This method will move object or player to the position where mouse is clicked on screen.
sorry for syntax error i have typed directly here
using UnityEngine;
using System.Collections;
public class MouseMovement : MonoBehaviour
{
public float speed = 10f;
bool isplayermove = false;
// Use this for initialization
private void Start ()
{
Vector3 playerpos = transform.position;
}
// Update is called once per frame
private void Update ()
{
if (Input.GetKeyDown(KeyCode.Mouse0))
{
is moveplayer = true;
}
if(ismoveplayer)
{
Vector3 mousePos = Camera.main.ScreenToWorldPoint(new Vector3(input.mousepos.x,input.mousepos.y,input.mousepos.z);
transform.position = Vector3.MoveTowards(transform.position,new Vector3(mousepos.x,transform.position.y,mousepos.z),speed * time.deltatime);
if(transform.position == mousepos)
{
ismoveplayer = false;
}
}
}
}

NavmeshAgent player not parallel to slope of hill when moving over hill

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);
}
}

Issues with a script that should follow another GameObject's position

I currently have a little issue with a script I made. Basically, I want to create a script that makes its GameObject (let's name it A) and follows another GameObject's (named B) position. I know a simple way to do that would be to parent A to B, but I'm not doing it for two reasons :
1) I want to be able to apply a smoothing (whose value I can change) on A's movement;
2) I want to be able to make A follow B's position and/or rotation at will.
Here is the script I wrote :
using UnityEngine;
using System.Collections;
public class FollowGameObject : MonoBehaviour {
public GameObject m_GameObjectToFollow;
public bool m_FollowPosition;
public bool m_FollowRotation;
public float m_PositionSmoothing;
public float m_RotationSmoothing;
// Should not be changed once set
public bool m_UseOffsetPosition;
public bool m_UseOffsetRotation;
private Vector3 m_PositionOffset;
private Quaternion m_RotationOffset;
void Start () {
m_PositionSmoothing = Mathf.Clamp(m_PositionSmoothing, 0.0f, 1.0f);
m_RotationSmoothing = Mathf.Clamp(m_RotationSmoothing, 0.0f, 1.0f);
if (m_UseOffsetPosition)
{
m_PositionOffset = transform.position - m_GameObjectToFollow.transform.position;
} else {
m_PositionOffset = Vector3.zero;
}
if (m_UseOffsetRotation)
{
m_RotationOffset = transform.rotation * Quaternion.Inverse(m_GameObjectToFollow.transform.rotation);
} else {
m_RotationOffset = Quaternion.identity;
}
}
void FixedUpdate () {
if (m_FollowPosition) {
Vector3 goalPosition = m_GameObjectToFollow.transform.position + m_PositionOffset;
transform.position = Vector3.Lerp(transform.position, goalPosition, m_PositionSmoothing);
//transform.Translate(newPosition - transform.position, Space.World);
}
if (m_FollowRotation) {
Quaternion goalRotation = m_GameObjectToFollow.transform.rotation * m_RotationOffset;
transform.rotation = Quaternion.Lerp(transform.rotation, goalRotation, m_RotationSmoothing);
}
}
I hope the code is easily understandable, if not feel free to ask.
In any case, once I attach this script to A and assign its m_GameObjectToFollow attribute to B (B is parented to a character controller, and I parented a sphere renderer to A so I can see if it follows B correctly), I notice that A is indeed following B, but I see that its position (through the sphere renderer) is "fluctuating" between the "right" position (B's) and another one. Visually, the sphere is flickering.
I tried putting the smoothing values to 1 (i.e. A should always be at B's position/rotation). I still see a flickering.
Could someone explain to me what I did wrong?
EDIT : Seems like I'm using Lerp the wrong way with its last value. I modified the script to use speed values instead of smoothing values, but still the same problem when I try to create some smooth movements (with lower speed values).
I have troubles explaining the problem properly. The best way to see what the problem look like would be to experience it yourself :
1) Create a scene with a terrain and a character controller in it;
2) Parent the main camera to the controller (so that it always follows it);
3) Create a new GameObject with a renderer (for example, a sphere), not parented to any other GameObject, but attach the following script to it :
using UnityEngine;
using System.Collections;
public class FollowGameObject : MonoBehaviour {
public GameObject m_GameObjectToFollow;
public bool m_FollowPosition;
public bool m_FollowRotation;
// Betzeen 0 and 1. 1 means that a complete unsmoothed follow
public float m_PositionFollowSpeed;
public float m_RotationFollowSpeed;
// Should not be changed once set
public bool m_UseOffsetPosition;
public bool m_UseOffsetRotation;
private Vector3 m_PositionOffset;
private Quaternion m_RotationOffset;
void Start () {
if (m_UseOffsetPosition)
{
m_PositionOffset = transform.position - m_GameObjectToFollow.transform.position;
} else {
m_PositionOffset = Vector3.zero;
}
if (m_UseOffsetRotation)
{
m_RotationOffset = transform.rotation * Quaternion.Inverse(m_GameObjectToFollow.transform.rotation);
} else {
m_RotationOffset = Quaternion.identity;
}
}
void Update () {
if (m_FollowPosition) {
Vector3 goalPosition = m_GameObjectToFollow.transform.position + m_PositionOffset;
transform.position = Vector3.Slerp(transform.position, goalPosition, Time.deltaTime * m_PositionFollowSpeed);
}
if (m_FollowRotation) {
Quaternion goalRotation = m_GameObjectToFollow.transform.rotation * m_RotationOffset;
transform.rotation = Quaternion.Slerp(transform.rotation, goalRotation, Time.deltaTime * m_RotationFollowSpeed);
}
}
}
With :
m_GameObjectToFollow = the character controller GameObject;
m_FollowPosition = true;
m_PositionFollowSpeed = 10;
(The other parameters values don't matter for this test)
Now start the scene and move the character controller, I will see the sphere flickering during motion, but if you stop moving it will smoothly go to the controller.
You are using FixedUpdate. Is there any special reason to do so?
Anyway, try to use Update or LateUpdate instead of FixedUpdate or check Fixed Timestep in Project Settings => Time.
Also read the answer to this question for more information about difference between Update and FixedUpdate.

Categories

Resources