Unity fix NavMeshAgent jerky movements? - c#

Record of the problem
https://youtu.be/BpzHQkVQz5A
Explaining my problem
I'm programming a mobile game using Unity3D Engine. For my player movement, I'm using NavMeshAgent because it's for me the easiest and most efficient way to do it. But when I hit the play button and ask my player to move, the movements are jerky and it's not pleasant to see at all.
Do you have any idea to fix this problem ?!
Thank you in advance for your answers ! ^^
My code
This is my code :
Player.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class Player : MonoBehaviour
{
NavMeshAgent agent;
Touch touch;
RaycastHit hit;
Ray ray;
// START FUNCTION
private void Start()
{
agent = GetComponent<NavMeshAgent>();
}
// UPDATE FUNCTION
private void Update()
{
// TOUCH DETECTION
if (Input.touchCount > 0)
{
touch = Input.GetTouch(0);
// A FINGER TOUCHED THE SCREEN
if (touch.phase == TouchPhase.Began)
{
// RETURN X, Y AND Z WORLD POS OF THE TOUCH SCREEN POS
ray = Camera.main.ScreenPointToRay(touch.position);
if (Physics.Raycast(ray, out hit))
{
if (hit.collider != null)
{
// MOVING PLAYER TO THE HIT POS
Vector3 hitVec = new Vector3(hit.point.x, hit.point.y + (GetComponent<Collider>().bounds.size.y / 2), hit.point.z);
agent.SetDestination(hitVec);
}
}
}
}
// SAME CODE USING MOUSE BUTTON
#if UNITY_EDITOR
if (Input.GetMouseButton(0))
{
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
if (hit.collider != null)
{
Vector3 hitVec = new Vector3(hit.point.x, hit.point.y + (GetComponent<Collider>().bounds.size.y / 2), hit.point.z);
agent.SetDestination(hitVec);
}
}
}
#endif
}
}
CameraFollow.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// BRACKEYS CAMERA FOLLOW SCRIPT WITHOUT THE LOOKAT METHODE
public class CameraFollow : MonoBehaviour
{
public Transform target;
public float smoothSpeed = 0.2f;
public Vector3 offset;
void FixedUpdate()
{
Vector3 desiredPosition = target.position + offset;
Vector3 smoothedPosition = Vector3.Lerp(transform.position, desiredPosition, smoothSpeed);
transform.position = smoothedPosition;
}
}

The problem isn't the navmesh controller but the camera follow script.
One thing you could try is to move the camera position using only the desiredPosition or use Vector3.SmoothDamp:
private Vector3 velocity;
void LateUpdate(){
...
Vector3 desiredPosition = target.position + offset;
Vector3 smoothedPosition = Vector3.SmoothDamp(transform.position, desiredPosition, ref velocity, smoothSpeed);
transform.position = smoothedPosition;
}
Also this is explained in a pinned comment on the Brackeys video

Related

how can I prevent the camera from sliding after it rotates around the player

I am new to game developing, and I am building a game with an orthographic camera,
the camera suppose to be following the player and when I click and drag the mouse it supposes to turn around him.
I managed to make the camera turn around the player, but when I add the code for the mouse drag when I hold the mouse it turns but when I release it slides.
This is my C# code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerFollow : MonoBehaviour {
public Transform PlayerTransform;
private Vector3 _cameraOffset;
[Range(0.01f, 1.0f)]
[SerializeField] float SmoothFactor = 0.5f;
[SerializeField] bool LookAtPlayer = false;
[SerializeField] bool RotateAroundPlayer = true;
[SerializeField] float RotationsSpeed = 5.0f;
// Use this for initialization
void Start () {
_cameraOffset = transform.position - PlayerTransform.position;
}
void LateUpdate () {
if (Input.GetMouseButtonDown(0))
{
RotateAroundPlayer = true;
}
else if (Input.GetMouseButtonUp(0))
{
RotateAroundPlayer = false;
}
if (RotateAroundPlayer)
{
Quaternion camTurnAngle =
Quaternion.AngleAxis(Input.GetAxis("Mouse X") * RotationsSpeed, Vector3.up);
_cameraOffset = camTurnAngle * _cameraOffset;
}
Vector3 newPos = PlayerTransform.position + _cameraOffset;
transform.position = Vector3.Slerp(transform.position, newPos, SmoothFactor);
if (LookAtPlayer || RotateAroundPlayer)
transform.LookAt(PlayerTransform);
}
}

Draw line between two game objects using linerenderer and raycast

What I'm trying to do is draw line between two gameobjects I'm using ray distance and line renderer but the line is too long. Below is my code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DrawLineTest : MonoBehaviour
{
RaycastHit hit;
public LineRenderer lineRender;
private void Awake()
{
lineRender = GetComponent<LineRenderer>();
}
void Start()
{
Ray ray = new Ray(transform.position, Vector3.down);
if (Physics.Raycast(ray, out hit))
{
if (hit.collider != null)
{
lineRender.enabled = true;
lineRender.SetPosition(0, transform.position);
lineRender.SetPosition(1, Vector3.down * hit.distance);
}
}
}
}
The second point is
lineRender.SetPosition(1, transform.position + Vector3.down * hit.distance);
or
lineRender.SetPosition(1, ray.GetPoint(hit.distance));
or more succinct
lineRender.SetPosition(1, hit.point);

Not understanding why raycast code isnt working

Here is the Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RaycastControl : MonoBehaviour
{
LineRenderer line;
private Vector3 zeros;
public LayerMask EnemyLayer;
// Start is called before the first frame update
void Start()
{
line = GetComponent<LineRenderer>();
zeros = new Vector3(0f, 0f, 0f);
}
// Update is called once per frame
void Update()
{
if (Input.GetButtonDown("Fire1"))
{
Debug.Log("Detected the click");
Vector3 mouse = mouseToWorld(Input.mousePosition);
Ray ray = new Ray(zeros, mouse);
RaycastHit hitData;
if (Physics.Raycast(ray, 10000, EnemyLayer))
{
Vector3[] linePos = new Vector3[] { transform.position, mouse };
line.SetPositions(linePos);
Debug.Log("You've hit a Zomboid!");
}
}
}
public Vector3 mouseToWorld(Vector3 mousePos)
{
mousePos = Input.mousePosition;
mousePos.z = Camera.main.nearClipPlane;
Vector3 mouse = Camera.main.ScreenToWorldPoint(mousePos);
mouse.z = 0f;
return mouse;
}
}
Note: I'm using Unity2d
I'm trying to use 0,0,0 and the location of my mouse to cast a ray starting from 0,0,0 and running through the mouse location on to the specified max distance in if(physics.Raycast(ray,maxDistance,EnemyLayer)). this, however, does not work. When I click on or behind the "Zombie" object I've created, I dont get a raycast hit detected.
I've been sure to make sure that the layer mask set in this script is the same one set in the Zombie object. My Debug.Log("You've made it this far!"); line activates so I know the Script is in the scene and is being read, but the Physics.Raycast(ray,10000,EnemyLayer)) NEVER returns true, and we know this because Debug.Log("You've hit a Zomboid!") never shows up in console.
Note: The object this script is attached to, Center, sits at 0,0,0. its transform.position = 0,0,0
Your help is greatly appreciated.
Physics and Physics2D are separate in Unity and don't interact with each other.
Physics2D.Raycast() belongs to Physics2D and only responds to Physics2D (BoxCollider2D, CircleCollider2D, PolygonCollider2D, etc.)
Physics.Raycast() belongs to Physics and only responds to Physics (BoxCollider, SphereCollider, MeshCollider, etc.)
You are using Physics.Raycast() when you should be using Physics2D.Raycast().
This is how you would do it:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RaycastControl : MonoBehaviour
{
LineRenderer line;
//private Vector3 zeros;
public LayerMask EnemyLayer;
// Start is called before the first frame update
void Start()
{
line = GetComponent<LineRenderer>();
//zeros = new Vector3(0f, 0f, 0f); not necessary this is the same as Vector3.zero
}
// Update is called once per frame
void Update()
{
if (Input.GetButtonDown("Fire1"))
{
Debug.Log("Detected the click");
RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
if (hit)
{
Vector3[] linePos = new Vector3[] { transform.position, hit.point};
line.SetPositions(linePos);
Debug.Log("You've hit a Zomboid!");
}
}
}
}```

Android Drag Sprite code Unity 5

I'm new to Unity and have been following a tutorial on how to make a Captain Blaster 2D game, however I want to convert it to Android, I want to make the player controllable by dragging him across the screen with one finger and don't understand what's wrong with my code, anything helps, thanks
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class ShipControl : MonoBehaviour {
public float playerSpeed = 10f;
public GameControl gameController;
public GameObject bulletPrefab;
public float reloadTime = 1f;
private float elapsedTime = 0;
void Update()
{
elapsedTime += Time.deltaTime;
if (Input.touchCount >= 1)
{
foreach (Touch touch in Input.touches)
{
Ray ray = Camera.main.ScreenPointToRay (touch.position);
RaycastHit hit;
if (Physics.Raycast (ray, out hit, 100)) {
}
}
if (elapsedTime > reloadTime)
{
Vector3 spawnPos = transform.position;
spawnPos += new Vector3 (0, 1.2f, 0);
Instantiate (bulletPrefab, spawnPos, Quaternion.identity);
elapsedTime = 0f;
}
}
}
void OnTriggerEnter2D(Collider2D other)
{
gameController.PlayerDied ();
}
}
What I would do is add a bool called "dragging" and after you check if Raycast hit anything you also check if hit object is the player GameObject.
If it is then as long as user is not releasing the touch - make player's rigidbody move towards the touch position (so if there are any obstacles it simply doesn't move right through them).
Code would probably look like this (you should also add some timer to check if player released touch and set dragging bool to false):
public float playerSpeed = 10f;
public GameControl gameController;
public GameObject bulletPrefab;
public float reloadTime = 1f;
private float elapsedTime = 0;
private bool dragging = false;
void Update()
{
if (Input.touchCount >= 1)
{
foreach (Touch touch in Input.touches)
{
Ray ray = Camera.main.ScreenPointToRay (touch.position);
RaycastHit hit;
if (Physics.Raycast (ray, out hit, 100))
{
if(hit.collider.tag == "Player") // check if hit collider has Player tag
{
dragging = true;
}
}
if(dragging)
{
//First rotate the player towards the touch (should do some checks if it's not too close so it doesn't glitch out)
Vector3 _dir = Camera.main.ScreenToWorldPoint(touch.position) - transform.position;
_dir.Normalize();
float _rotZ = Mathf.Atan2(_dir.y, _dir.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(0f, 0f, _rotZ - 90);
//Move towards the touch
transform.GetComponent<Rigidbody>().AddRelativeForce(direction.normalized * playerSpeed, ForceMode.Force);
}
}
}
}

Unity3D with C# to achieve Click To Move

I've a problem when I use unity3D with C# to achieve Click To Move.
It means the character move to where my mouse clicked.
But when my character move to destination,it will span itself.
I think it's perhaps wrong in this line
"controller.SimpleMove (transform.forwardspeed);"
when I click to position like(20.5,10.1) with decimal point or some number I can't present in "transform.forwardspeed" ,cause my character can never achieve to this position but keep trying to. So my character span and span.....
It's my guess right?
If true ,how can I fix it?
This is my Script for ClickToMove
using UnityEngine;
using System.Collections;
public class ClickToMove : MonoBehaviour {
public float speed;
public CharacterController controller;
private Vector3 position;
public int arrive =1;
void Start ()
{
}
void Update ()
{
if (Input.GetMouseButton (0))
{
//Locate where we click
locatePosition();
}
MoveToPos ();
//Move to where we click
}
void locatePosition()
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (ray, out hit, 1000))
{
position = new Vector3(hit.point.x,hit.point.y,hit.point.z);
Debug.Log(position);
}
}
void MoveToPos()
{ if (Vector3.Distance (transform.position, position) > 1)
{
Quaternion newRotation = Quaternion.LookRotation (position - transform.position);
newRotation.x = 0f;
newRotation.z = 0f;
transform.rotation = Quaternion.Slerp (transform.rotation, newRotation, Time.deltaTime * 10);
controller.SimpleMove (transform.forward*speed);
}
}
}

Categories