and nothing on there helps with my problem. This is the code I am working off of now for simplistic reasons.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Tilt : MonoBehaviour
{
public LayerMask mask;
void Update()
{
RaycastHit hit;
if (Physics.Raycast(transform.position, -Vector3.up, out hit, 0.5f, mask))
{
transform.up = hit.normal;
}
}
}
The problem is that my “tank” is always facing forward but this code does work when it comes to aligning with an angle using unity’s Navmesh.
This script is attached to the “tank”, which has a kinematic rigidbody attached and a box collider set to isTrigger.
It could be that the raycast hits the tank’s own collider, hence causing it to align its up-axis with itself.
This is a very common problem, and the solution is to simply offset your raycast origin to ensure it is not within your object’s collider.
Ok, I’ve created an offset for the ray so that the ray doesn’t touch its own gameObjects collider, but now it starts to freak out when it goes on an angle, right now it turns on a plane, the gameObject must be perpendicular to the ground in order for it to rotate on the z-axis, but as soon as it gets an angle, it will not turn, or align to the ground, and it faces directly ahead, as before. Here is the updated script. The referencePos is just an empty child of the gameObject for the ray to start from.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Tilt : MonoBehaviour
{
public LayerMask mask;
public Transform referencePos;
void Update()
{
RaycastHit hit;
if (Physics.Raycast(referencePos.position, Vector3.down, out hit))
{
transform.up = hit.normal;
}
}
}
since transform.down doesn’t exist, I replaced it with -transform.up, which is essentially the same of course. I can show you pictures of what’s happening with the current script later today to give a better understanding of what’s happening.
Alright, here are four pictures to better demonstrate what this code below is doing,
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Tilt : MonoBehaviour
{
public LayerMask mask;
public Transform referencePos;
void Update()
{
RaycastHit hit;
if (Physics.Raycast(referencePos.position, -transform.up, out hit))
{
transform.up = hit.normal;
}
}
}
This first picture has a purple dot, which is the reference point for the ray
The next image shows the behaviour of the gameObject, the arrows on the slope describes it’s random jerking motion as it tries to turn on the slope (Turns towards the “point”, y=0, turns, y=0…). This effect happens: On the slope, or during the transition between the plane and the slope. It is also not aligned.
I turned it off. Same results. I believe that this issue has something to do with the update function. By setting the z-axis to 0 if the ray detects the ground. The update function ensures that it won’t rotate the z axis freely if the ground is always beneath it. I’m thinking of a messy solution by using a coroutine but there’s got to be a better way. I’m pretty sure that is the issue.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Tilt : MonoBehaviour
{
public LayerMask mask;
public Transform referencePos;
[HideInInspector]
public PlayerControl plCtrl;
[HideInInspector]
public Vector3 hitPoint;
void Update()
{
RaycastHit hit;
if (Physics.Raycast(referencePos.position, Vector3.down, out hit))
{
transform.up = hit.normal;
transform.LookAt(hitPoint);
}
}
}
It’s kind of weird, but in short, if it the ray hits the terrain, it’s going to look at the angle of the destination or (hit.point(derived from another script)) while still being able to align to the ground. If anyone is wondering, the “PlayerControl” script is found when the ray from the camera(which contains the PlayerControl script) hits this gameObject, finds the “Tilt” script where the ray hit, and then plCtrl is null then equal to GetComponent();
Thank you Yandalf for the time you’ve put in to help me find the solution.
I have vastly improved my problem, it is now fixed, and optimized and smooth and nice to watch. Part of my issue was that the actual gameObject was not imported correctly from blender in terms of rotation, anyone who has a problem with rotation can be referred to here:
.
Secondly, I had very poor skills in attempting my own solution, but here it is. This script will work on a navmesh of any kind of surface, and always rotate correctly and smoothly. It works SO well! I thought I would share this for someone who has had a similar problem.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Tilt : MonoBehaviour
{
public LayerMask mask;
void Update()
{
RaycastHit hit;
if (Physics.Raycast(transform.position, -transform.up, out hit))
{
var slopeRotation = Quaternion.FromToRotation(transform.up, hit.normal);
transform.rotation = Quaternion.Slerp(transform.rotation, slopeRotation * transform.rotation, 10 * Time.deltaTime);
}
}
}
Thank you! This works perfectly! I adjusted value “10” to 0.5f to stop the jittering on the slopes. I watch so many videos on how to do this, some 43mins long and in just a few lines of code it’s solved. Blessings
BRAVO. This works perfectly. I have the navmesh agent component on a parent and i put this script on the model child and it is 100% what i wanted. Thank you
Hey guyz, I was hoping to do this without a costly raycast. It took me a while but i got it and it can even interpolate nicely. You can improve it, if you sample more positions. You’re welcome
private void AlignWithNavMesh()
{
if (NavMesh.SamplePosition(transform.position + (transform.forward * _agent.radius), out NavMeshHit navMeshHit, _agent.radius * 2f, NavMesh.AllAreas))
{
var hitPos = navMeshHit.position;
hitPos.y += _agent.baseOffset;
var lookVector = hitPos - transform.position;
if (lookVector.sqrMagnitude > float.Epsilon)
{
transform.rotation = Quaternion.LookRotation(lookVector, Vector3.up);
}
}
}
Hey dude .Your code seems have some problems because the hit navmeshit position would not hit on the slope surface of terrain. it only works in basic mesh. And I believe it’s better to use physics raycast initing the whole world navmesh and saving it to a data such as scriptable objects using Hashset<Vector3,Vector3> to sample the map,after which we only need to read this data and do LookRotation.No need for calculating runtime at all.