I'm currently learning Unity. I have learnt and did many projects and started making a new one about cars. My goal is NOT to achieve realistic physics. I'm trying to have a 0 slip.
I have done all the steps about the wheelcolliders, velocity, rotation, and overall movement. Currently I'm struggling to disable the car slip.
I don't want the car to slip at all. I tried using transform and change the position, but that isn't the method that I want to use.
Using the following method, I'm doing the acceleration:
private void doAccelerate() {
currentSpeed = (int) (rb.velocity.magnitude * 3.6f);
if (!hasBraked) {
if (hasReachedMax) {
rb.velocity = new Vector3(rb.velocity.x, rb.velocity.y, maxVelocity);
} else {
if (currentSpeed < maxSpeed) {
rearDriverW.motorTorque = m_verticalInput * motorForce * motorAccelerate;
rearPassengerW.motorTorque = m_verticalInput * motorForce * motorAccelerate;
} else if (currentSpeed > maxSpeed) {
hasReachedMax = true;
}
}
}
}
The following two pics provide the UI units for the Rigidbody and WheelColliders.
This pic, and this one.
I would some suggestions to apply 0 slip. I have tried playing with the value, yet I didn't reach the perfect values. Nevertheless, I didn't understand it correctly. That's why I didn't know.
Related
I am trying to create a procedural gun controller, but I can't find why my gun behaves so weird when I change the fire mod to automatic. To understand this better, I will give an example: when I try to shoot by pressing the "Mouse0" key, on semi auto mod it works fine, it behaves like I want it to (the bolt kicks back when I shoot, the front barrel kicks back - I animate them with code instead of frame animations from Unity or a 3rd party soft like Blender), but..., when I change to automatic, the problem is not that I get errors, The animations of the moving pieces don't work as they should and are not triggered correctly.
I tried to use different methods for shooting(using the WaitForSeconds() and WaitForSecondsRealtime() while using coroutines). It didn't work. I tried using the time function with scaled and unscaled time in the update function. I still got the same results.
What should I do to?
This is the shoot function untill now:
void GunFireManagement()
{
if (fireType == fireMethod.single)
{
foreach (BlowBack anim in animations)
{
if (Input.GetKeyDown(KeyCode.Mouse0))
{
gunSoundClone = Instantiate(gunShootSound, this.transform.position, Quaternion.identity) as GameObject;
anim.piece.transform.position = anim.kickbackState.transform.position;
}
if (anim.piece.transform.position != anim.initialPosition.transform.position)
{
anim.piece.transform.position = Vector3.Lerp(anim.piece.transform.position, anim.initialPosition.transform.position, anim.speed);
}
Destroy(gunSoundClone, 0.5f);
}
}
if (fireType == fireMethod.auto)
{
foreach (BlowBack anim in animations)
{
if (Input.GetKey(KeyCode.Mouse0) && Time.time - lastFired > 1f/autoFireRate)
{
lastFired = Time.time;
gunSoundClone = Instantiate(gunShootSound, this.transform.position, Quaternion.identity) as GameObject;
anim.piece.transform.position = anim.kickbackState.transform.position;
}
if (anim.piece.transform.position != anim.initialPosition.transform.position)
{
anim.piece.transform.position = Vector3.Lerp(anim.piece.transform.position, anim.initialPosition.transform.position, anim.speed);
}
Destroy(gunSoundClone, 0.5f);
}
}
}
The issue is how you are using Vector3.Lerp. The first two arguments you pass to the method are supposed to be the start and end positions of the animation, and the third one, t, is supposed to be the progress of the animation from the start towards the end, as a value between 0 and 1.
You can calculate the value of t by dividing the time since the shot started with the duration of the animation. For example if the length of the animation is 2 seconds, and the short started 1 second ago, then t should be 0.5.
if(isFiring)
{
float timeSinceShotStart = Time.deltatime - lastFired;
// t = s / v
float animationDuration = 1f / anim.speed;
UpdateBlockBackAnimationState(timeSinceShotStart / animationDuration);
}
}
private void SetBlowBackAnimationState(float progress01)
{
foreach(BlowBack anim in animations)
{
Vector3 initialPosition = anim.initialPosition.transform.position;
Vector3 finalPosition = anim.finalPosition.transform.position;
anim.piece.transform.position = Vector3.Lerp(initialPosition, finalPosition, progress01);
}
}
I recommend you try to split up your code into smaller methods that are easier to understand. You are trying to do so many things in one generic "GunFireManagement" method that it becomes pretty difficult to keep track of all the different pieces :)
I also recommend considering using a tweening framework such as DOTween to make it easier to animate things over time.
I'm trying to come up with a calculated way to compare current speed vs distance to the next waypoint, with the end goal that the computer car makes a decision to "coast," brake, or keep the throttle on in the best way while turning the best way possible so that it doesn't OVERSHOOT the waypoint (like the Standard Unity assets car currently does when using the waypoint AI). I feel like there's a few things I'm failing to grasp, however. I've had to set up a TON of barriers and something I call "PowerZones" (zones that control the amount of brake and engine torque on the car in terms of percentages). Here's my current course below, which is of course incomplete in waypoints, but the point is to note how many of these zones and obstacles there is. I really don't feel there should HAVE to be this many!
However, the reason that I have SO many is because it's been kinda difficult for me to come up with an ideal function to optimize these kinds of driving and steering decisions as the opponent. Here's the Drive and Steer functions for the vehicle (some of which are based on an existing Eyemaginary tutorial):
private void Drive()
{
float currDistFromWP = Vector3.Distance(transform.position, nodes[currentNode].position);
float speed = rb.velocity.magnitude;
float timeFloatLeft = currDistFromWP / speed;
Vector3 relativeVector = transform.InverseTransformPoint(nodes[currentNode].position);
float newSteer = (relativeVector.x / relativeVector.magnitude);
Debug.Log("Steer to set: " + newSteer);
Debug.Log("Current distance: " + currDistFromWP);
if ((timeFloatLeft < 1f || Mathf.Abs(newSteer) > .5f) && speed > 5)
{
Debug.Log("Coasting...");
im.throttle = 0;
}
else
{
im.throttle = 1;
}
}
private void ApplySteer()
{
if (avoiding)
return;
Vector3 relativeVector = transform.InverseTransformPoint(nodes[currentNode].position);
float newSteer = (relativeVector.x / relativeVector.magnitude);
im.steer = newSteer;
}
Here is my waypoint updating function:
private void CheckWaypointDistance()
{
float currDistFromWP = Vector3.Distance(transform.position, nodes[currentNode].position);
//Debug.Log("Current distance from waypoint: " + currDistFromWP);
if (currDistFromWP < 1.1f)
{
im.brake = false;
if(currentNode == nodes.Count - 1)
{
currentNode = 0;
}
else
{
currentNode++;
}
}
else if (currDistFromWP < 10f)
{
im.brake = true;
}
}
I feel like I could be making this harder than I need to somehow. Or maybe I'm just needing to consider more variables. Does anyone have any tips to make this a little more tight in terms of AI logic? I'm happy to show more code if needed, but the idea is to have a Car Controller class that's used by BOTH the player and AI to DRIVE the car, and then the AI making the best decisions in a way the player would need to drive it in a separate class. The code from above is the separate AI decision making component.
In a Unity VR app I'm building, I'm trying to rotate an object that is currently 'being held'. The technique I'm using is to find the desired rotation and feed it into the target objects Rigidbody via Rigidbody.MoveRotation. This works well when I use a test quaternion exposed in the inspector, but my quaternion math is completely failing me when it comes to finding the target rotation I want. I've got the position tracking working perfectly, it's just the rotation thats killing me!
The desired outcome is that the target object in question keeps its current rotation (from the moment its picked up) and simply applies the frame-by-frame difference of the VR controller. I thought this would be pretty straight forward, but I'm getting strange results. This is what I have so far:
public Rigidbody targetRigidbody;
public Quaternion controllerRotationSnapshot;
public Quaternion targetRotationSnapshot;
public float grabRadius = 0.25f;
public Collider[] grabResults;
Quaternion deltaRotation;
void Awake() {
grabResults = new Collider[5];
}
// This is triggered externally
public void Pickup() {
Physics.OverlapSphereNonAlloc(transform.position, grabRadius, grabResults);
for (int i = 0; i < grabResults.Length; i++) {
if (grabResults[i] != null) {
if (grabResults[i].CompareTag("Grabbable")) {
targetRigidbody = grabResults[0].GetComponent<Rigidbody>();
targetRotationSnapshot = targetRigidbody.transform.rotation;
i = grabResults.Length;
}
}
}
controllerRotationSnapshot = transform.rotation;
}
public void LetGo() {
if (!targetRigidbody) {
return;
}
targetRigidbody = null;
grabResults = new Collider[5];
}
void FixedUpdate() {
if (!targetRigidbody) {
return;
}
Quaternion deltaRotationDifference = transform.rotation * Quaternion.Inverse(controllerRotationSnapshot);
targetRigidbody.MoveRotation(targetRotationSnapshot * deltaRotationDifference);
}
It works perfectly as long as the target object is at a rotation of 0,0,0 (in euler angles). But the moment the target object is picked up with a different rotation at all (i.e. [X: 20, Y: -5, Z: 325] or something), the frame-by-frame controller difference (a 'delta rotation' I've heard this called?) gets applied on a completely different axis. It's very confusing because as far as I can tell, nothing about my code is applied locally, it's all using global calculations?
I've done a lot of Googlin' and can't find an answer at all, any help is greatly appreciated.
I have the following code which adds force to a rigidbody2d in a random direction and attempts to set the linear drag to 0 when a specific speed is reached, essentially letting the gameobject slowly float away.
The problem is that the drag seems to be set to 0 straight away, and I do not understand why, and therefore I am unable to solve the problem
void Update () {
if (Input.GetKeyDown ("space")) {
rb.velocity = Vector3.zero;
Vector3 dir = Random.onUnitSphere;
rb.AddForce (dir * 10, ForceMode2D.Impulse);
}
if (rb.velocity.magnitude <= 1) {
rb.drag = 0;
}
}
Thank you
Crouz
As #Maakep said, the problem comes from the fact you set the Rigidbody velocity to 0 and check if this velocity is <= 1 right afterward (the force is only applied later).
To solve your problem you could do something like this:
public bool applyNextFrame = false;
protected override void Update()
{
if(applyNextFrame && rb.velocity.magnitude <= 1)
{
rb.drag = 0;
applyNextFrame = false;
}
if(Input.GetKeyDown(KeyCode.Space))
{
rb.velocity = Vector3.zero;
Vector3 dir = Random.onUnitSphere;
rb.AddForce(dir * 10, ForceMode2D.Impulse);
applyNextFrame = true;
}
}
Keep in mind this solution is far from flawless since you can have a problem if your Rigidbody configuration (mass, drag and force applied) applies different velocity values: therefore, you won't be able to fully control when the drag will reach 0 (this may be completely intentional depending on your project !) :)
You can look to the execution order diagram located in this page for further information: you can see the Internal physics update happens before the Update() (when you call rb.AddForce(...) it's actually only applied during the next Internal physics update).
Also note I changed Input.GetKeyDown("space") to Input.GetKeyDown(KeyCode.Space): this avoids typo problems if you mistype space.
Hope this helps,
I'm using the latest googleVr SDK(1.10) but I tested some example scenes from unity like castle defence and I notice the view began to drift when I put the phone on the table. is there a way to prevent this drift programatically?
I saw some videos to correct the gyroscope on samsung but I want some code to prevent this
It's still a non solved issue, as explained in this post:
GvrViewerMain rotates the camera yourself. Unity3D + Google VR
But according to your needs, you may find usefull the following workaround.
The idea is to find the delta rotation and ignore it if too small.
using UnityEngine;
public class GyroCorrector {
public enum Correction
{
NONE,
BEST
}
private Correction m_correction;
public GyroCorrector(Correction a_correction)
{
m_correction = a_correction;
}
private void CorrectValueByThreshold(ref Vector3 a_vDeltaRotation, float a_fXThreshold = 1e-1f, float a_fYThreshold = 1e-2f, float a_fZThreshold = 0.0f)
{
// Debug.Log(a_quatDelta.x + " " + a_quatDelta.y + " " + a_quatDelta.z );
a_vDeltaRotation.x = Mathf.Abs(a_vDeltaRotation.x) < a_fXThreshold ? 0.0f : a_vDeltaRotation.x + a_fXThreshold;
a_vDeltaRotation.y = Mathf.Abs(a_vDeltaRotation.y) < a_fYThreshold ? 0.0f : a_vDeltaRotation.y + a_fYThreshold;
a_vDeltaRotation.z = Mathf.Abs(a_vDeltaRotation.z) < a_fZThreshold ? 0.0f : 0.0f;//We just ignore the z rotation
}
public Vector3 Reset()
{
return m_v3Init;
}
public Vector3 Get(Vector3 a_v3Init)
{
if (!m_bInit)
{
m_bInit = true;
m_v3Init = a_v3Init;
}
Vector3 v = Input.gyro.rotationRateUnbiased;
if (m_correction == Correction.NONE)
return a_v3Init + v;
CorrectValueByThreshold(ref v);
return a_v3Init - v;
}
}
... And then use something like this in the "UpdateHead" method from "GvrHead":
GvrViewer.Instance.UpdateState();
if (trackRotation)
{
var rot = Input.gyro.attitude;//GvrViewer.Instance.HeadPose.Orientation;
if(Input.GetMouseButtonDown(0))
{
transform.eulerAngles = m_gyroCorrector.Reset();
}
else
{
transform.eulerAngles = m_gyroCorrector.Get(transform.eulerAngles);//where m_gyroCorrector is an instance of the previous class
}
}
You may find some problems. Mainly but not exclusive:
There will be a latence problem when moving the head as there is an offset to detect the movement
You are dealing with relative positions that come with imprecisions. So you are not 100% sure to find the same position
when doing the opposite movement.
You are using euler representation instead of quaternion, and it seems to be less accurate.
You may also be interested in these links speaking about the field:
http://scholarworks.uvm.edu/cgi/viewcontent.cgi?article=1449&context=graddis
Gyroscope drift on mobile phones
and this piece of code :
https://github.com/asus4/UnityIMU
Hope it can help,