calculate dynamic stoppingDistance in unity - unity3d

For control NammeshAgent and stop after reach to destination i used OnAnimatorMove(). but when it reached to destination, run animation won't stop.
I used BlendTree for control animations. so this is my code:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
// private vriables
private Animator anim;
private NavMeshAgent navAgent;
public Transform target;
private float speed;
void Start()
{
anim = GetComponent<Animator>();
navAgent = GetComponent<NavMeshAgent>();
}
void Update()
{
MoveToDestination();
}
private void MoveToDestination()
{
// Move to Target
if (Vector3.Distance(transform.position, target.position) > navAgent.stoppingDistance)
{
speed = 1f;
navAgent.SetDestination(target.position);
}
else
{
speed = 0;
}
anim.SetFloat("Speed", speed, 0.1f, Time.deltaTime);
}
private void OnAnimatorMove()
{
navAgent.speed = (anim.deltaPosition / Time.deltaTime).magnitude;
}
NOTE: when NavmeshAgent is reached to destination, speed value in NavmeshAgent Component is greater than 1. i seen this with print below line.
Vector3.Distance(transform.position, target.position)
NOTE: I set stoppingDistance to 0 in NavMesh Component.
So i need calculate stoppingdistance dinamically between player and target.

Some minor problems with your code:
you set speed = 0; but I don't see speed anywhere defined, except for navAgent.speed - make sure you use the correct/intended variable!
Vector3.Distance(transform.position, target.position) > navAgent.stoppingDistance is basically distance > 0 - replace stoppingDistance with 0.2f or some other small value. The distance will almost never be exactly zero, therefore (almost) always > 0.
Some thoughts:
You could set the speed of your animations to the agent speed, so the animation would "run" but not actually move if the player won't move. Also it would scale with acceleration automatically. Maybe your blendTrees would work better then, too.
Why did you put stopping distance to 0?

problem was in this part and i removed it.
private void OnAnimatorMove()
{
navAgent.speed = (anim.deltaPosition / Time.deltaTime).magnitude;
}
and also i set stoppingDistance to none zero.

Related

Need help refactoring script to find closest target

I have an asteroid field spawned at runtime and droid prefabs the player can release to gather raw material from the asteroids. Everything works but the droids go to the furthest part of the asteroid field to start collecting. I realize I likely need a list of objects to sort through somehow and output the closest.
I suck at coding but managed to get this working by getting a link to the spawned asteroids adding MovementAIRigidbody target to this script & finding one with target = GameObject.Find("AsteroidNew2(Clone)").GetComponent().
This script is based on a GitHub MIT project which is using Vector3 targetPos; I believe to select the target position. Hope this makes sense to a kind soul out there.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace UnityMovementAI
{
public class OffSetPursuitUnityMy : MonoBehaviour
{
MovementAIRigidbody target;
public Vector3 offset;
public float groupLookDist = 1.5f;
SteeringBasics steeringBasics;
OffsetPursuit offsetPursuit;
Separation separation;
NearSensor sensor;
void Start()
{
steeringBasics = GetComponent<SteeringBasics>();
offsetPursuit = GetComponent<OffsetPursuit>();
separation = GetComponent<Separation>();
target = GameObject.Find("AsteroidNew2(Clone)").GetComponent<MovementAIRigidbody>();
sensor = GameObject.Find("SeparationSensor").GetComponent<NearSensor>();
}
void LateUpdate()
{
Vector3 targetPos;
Vector3 offsetAccel = offsetPursuit.GetSteering(target, offset, out targetPos);
Vector3 sepAccel = separation.GetSteering(sensor.targets);
steeringBasics.Steer(offsetAccel + sepAccel);
/* If we are still arriving then look where we are going, else look the same direction as our formation target */
if (Vector3.Distance(transform.position, targetPos) > groupLookDist)
{
steeringBasics.LookWhereYoureGoing();
}
else
{
steeringBasics.LookAtDirection(target.Rotation);
}
}
}
}

Why does exporting to Unity WebGL change the speed of objects in my game?

GOAL
So I have a space-invaders type game I have made to practise unity and I want to upload it to Itch.io as I have done in the past.
This is a clip of the game.
I switched platforms to WebGL in Build Settings etc, and everything worked fine in Unity.
PROBLEM
However when I built it and uploaded the zip file to Itch.io, the aliens are now a lot faster than usual. (Be aware there may be other things that have changed, I just haven't been able to get to them since it is extremely hard).
CODE
Alien movement:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class AleenController : MonoBehaviour
{
Rigidbody2D rigidbody;
public float speed = 10f;
ScoreController scoreController;
AudioSource aleenDie;
void Start()
{
scoreController = GameObject.Find("Canvas/Score").GetComponent<ScoreController>();
rigidbody = GetComponent<Rigidbody2D>();
aleenDie = GameObject.Find("Main Camera/AleenDie").GetComponent<AudioSource>();
}
void Update()
{
rigidbody.MovePosition(transform.position + new Vector3 (0, -1, 0) * speed * Time.deltaTime);
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == "laser")
{
aleenDie.Play();
scoreController.score += 1;
Destroy(gameObject);
}
}
}
NOTE
I am really struggling to find out what is wrong here, since everything is fine in unity. If you do need more details just leave a comment.
If you use physics you should
not set or get values via Transform at all
do things in FixedUpdate
In general though in your case instead of using
void Update()
{
rigidbody.MovePosition(transform.position + new Vector3 (0, -1, 0) * speed * Time.deltaTime);
}
at all simply set the velocity once like e.g.
void Start ()
{
...
rigidbody.velocity = Vector3.down * speed;
}
The rest seems to depend a bit on your screen size. Looks like you are moving your elements in pixel space -> the smaller the display the less pixel distance between the top and bottom -> the faster elements seem to travel.

Unity 3d Quaternion Rotation Lerp of 3d Object

I am working on a Unity project. There is a car wiper and i want to rotate it in a way that when I pres "wipers toggle on" wipers start rotating from 0,0,0 to 0,0,-45 and start lerping. But when I press "wipers toggle off" the wipers must rotate back to 0,0,0. For example if current wipers rotation are 0,0,-20 and I press the "wipers toggle off" key they wipers must be rotateTowards 0,0,0. Also, If I press "wipers toggle on" again the wipers must start rotating from 0,0,0 to 0,0,-45. Now, the situation is that Wipers are rotating but when I press "wipers toggle off" the wipers stop at exactly the same current rotation point where they are for example (0,0,-30). And when I press "wipers toggle on" again the wipers starts from weird different rotation point. Here is my code:
using UnityEngine;
using System.Collections;
public class Wipers : MonoBehaviour
{
[SerializeField] protected Vector3 m_from = new Vector3(0.0F, 0.0F, 0.0F);
[SerializeField] protected Vector3 m_to = new Vector3(0.0F, -45.0F, 0.0F);
[SerializeField] protected float m_frequency = 1.0F;
protected virtual void Update()
{
if (ControlFreak2.CF2Input.GetAxis ("wipers") != 0)
{
Quaternion from = Quaternion.Euler(this.m_from);
Quaternion to = Quaternion.Euler(this.m_to);
float lerp = 0.5F * (1.0F + Mathf.Sin(Mathf.PI * Time.realtimeSinceStartup * this.m_frequency));
this.transform.localRotation = Quaternion.Lerp(from, to, lerp);
}
}
}
Your issue when turning on is that you are directly using Time.realtimeSinceStartup which also continues running while the routine is turned off of course! So you never know at which point the wipers will be when turned on.
&rightarrow; You rather want to use the time since the wipers where started instead.
Your issue when turning off is of course that you immediately stop moving.
&rightarrow; You rather want to always complete a full cycle after the wipers have been turned off.
Instead of doing this in Update I would suggest to use a Coroutine. Coroutines are way easier to control and maintain than doing stuff in Update directly. In fact they are like small temporary Update like routines and execute right after the real Update has finished.
A Coroutine you can let continue and complete a full cycle until it is actually done.
In Update you would only check the user input and start a routine (if none is running already) and the routine can run and terminate a complete cycle independently:
[SerializeField] protected Vector3 m_from = new Vector3(0.0F, 0.0F, 0.0F);
[SerializeField] protected Vector3 m_to = new Vector3(0.0F, -45.0F, 0.0F);
[SerializeField] protected float m_frequency = 1.0F;
// TODO only for debugging
[SerializeField] private bool ControlFreak2Dummy;
private bool wipersOn;
private Quaternion from;
private Quaternion to;
private void Awake()
{
// Store these once -> more efficient then recalculate them everytime
from = Quaternion.Euler(m_from);
to = Quaternion.Euler(m_to);
}
protected virtual void Update()
{
// TODO switch these back
//if (ControlFreak2.CF2Input.GetAxis ("wipers") != 0)
if (ControlFreak2Dummy)
{
if(!wipersOn)
{
StartCoroutine(Wipers());
}
}
}
// To make things easier for us this in itself closed routine is exactly ONE FULL wipers cycle
// so we can determine exactly when a full cycle is done or not
private IEnumerator Wipers()
{
// block concurrent routines
wipersOn = true;
var duration = 1f / m_frequency;
var timePassed = 0f;
while (timePassed <= duration)
{
// Note: Your sinus factor calculation was a bit strange
// (or maybe this early I'm way too stupid for maths lol ^^)
// It was always minimum 0.5 and maximum 1, you rather want to pingpong between 0 and 1
//
// This now moves forth and back exactly once between 0 and 1
var factor = Mathf.Sin(Mathf.PI * timePassed / duration);
transform.localRotation = Quaternion.Lerp(from, to, factor);
// increase timePassed by the time passed since last frame
timePassed += Time.deltaTime;
// allows Unity to "pause" here, render this frame and
// continue from here in the next frame
yield return null;
}
// make sur it really terminates in 0
transform.localRotation = from;
// tell others that this routine is done
wipersOn = false;
}

Unity ball with constant speed

I'm making 2D mobile game and I have a ball, but my ball doesn't have a constant moving speed. What I need to do?
When I build game on my android device, ball have a various speed. In that case, my game is not playable.
I hope that someone can help me. Thanks.
This is on my start function:
void Start () {
GetComponent<Rigidbody2D> ()
.AddForce (new Vector2 (1f, 0.5f)* Time.deltaTime * force);
}
Is it a good practice if I used in code " Application.LoadLevel ("__Scena_0"); " to load existing scene when I lose " life" ? Problem happens when I lost " life " and try playing game in second chance.
My update function is about OnTriggerEnter2D when my ball hit trigger objects.
EDIT 23.12.2015. : problem solve with adding physics material (fiction 0) and adding to script:
using UnityEngine.SceneManagement;
...
SceneManager.LoadScene ("MainScene");
The problem is the calculation of the force vector:
new Vector2 (1f, 0.5f) * Time.deltaTime * force
You are using Time.deltaTime as a factor, which means that the applied force is not constant, but depending on the deltaTime, which is the duration of the last frame. This explains why it changes randomly.
I don't think Time.deltaTime is what you want here, try just removing the factor and adjusting the "force" factor accordingly. You should now have a constant force applied, independent from the platform you play on.
Create a new Physics Material, set friction zero and add it to your object. If your object has no friction, its speed cannot be decreased. Then, use AddForce() on Rigidbody2D to speed up.
Assuming that your ball and colliding walls have bouncy materials with no friction. Try
public float _ballSpeed = 2.5f;
Rigidbody2D _rb;
void Start()
{
_rb = GetComponent<Rigidbody2D>();
_rb.velocity = Vector2.one * _ballSpeed;
}
void Update()
{
}
From this you can control ball speed through _ballSpeed
//========== OR ==========//
If you want to retain speed even after ball destruction.
Retain _ballSpeed in any global static variable.
Suppose you have a class named Globals, declare a variable like,
public class Globals
{
public static float BALL_SPEED = 2.5f;
}
Now in Ball Script
Rigidbody2D _rb;
void Start()
{
_rb = GetComponent<Rigidbody2D>();
_rb.velocity = Vector2.one * Globals.BALL_SPEED;
}
void Update()
{
}

How to add friction to a Wheel of Fortune in Unity3D

First of all I am new to unity as will as C#. I want to create a Wheel of Fortune for my game using C# where you can rotate it with the mouse. I wrote this code in C# - it works well, the only problem is I don’t know how to add friction to it so that if I release the mouse button it still continues rotating and slows down until it is fully stopped (Just like a realistic Fortune Wheel).
using UnityEngine;
using System.Collections;
public class RotateCSharp : MonoBehaviour
{
public int speed;
public float lerpSpeed;
float xDeg;
float yDeg;
Quaternion fromRotation;
Quaternion toRotation;
void Update()
{
if (Input.GetMouseButton(0))
{
xDeg -= Input.GetAxis("Mouse X") * speed;
fromRotation = transform.rotation;
toRotation = Quaternion.Euler (yDeg,xDeg,0);
transform.rotation = Quaternion.Lerp(fromRotation, toRotation, Time.deltaTime * lerpSpeed);
}
}
}
How can I accomplish this?
Full Disclosure--I don't do Unity, and not much C#, but this is mostly math.
Friction from sliding or rolling is almost exactly constant deceleration. Deceleration is negative acceleration, and acceleration is (velocity change)/(elapsed time).
Figure out how long you want the wheel to spin at a the maximum initial angular speed you'll allow, and that speed/time ratio is your deceleration rate. That's a constant for the wheel.
Now, in the code either before or after adjusting the angular position, decrease the speed by the deceleration rate * time interval, being careful not to overshoot 0:
if (speed > 0)
speed = Math.max(0, speed - decelRate*Time.deltaTime);
else
speed = Math.min(0, speed + decelRate*Time.deltaTime);
That assumes that decelRate is a positive value, and will handle spins in either direction.
You may have to adjust the syntax a bit, but that's the basic idea.
I've put together a behaviour that applies friction on a hinge joint. Here it is:
using UnityEngine;
public class JointFriction : MonoBehaviour {
[Tooltip("mulitiplier for the angular velocity for the torque to apply.")]
public float Friction = 0.4f;
private HingeJoint _hinge;
private Rigidbody _thisBody;
private Rigidbody _connectedBody;
private Vector3 _axis; //local space
// Use this for initialization
void Start () {
_hinge = GetComponent<HingeJoint>();
_connectedBody = _hinge.connectedBody;
_axis = _hinge.axis;
_thisBody = GetComponent<Rigidbody>();
}
// Update is called once per frame
void FixedUpdate () {
var angularV = _hinge.velocity;
//Debug.Log("angularV " + angularV);
var worldAxis = transform.TransformVector(_axis);
var worldTorque = Friction * angularV * worldAxis;
_thisBody.AddTorque(-worldTorque);
_connectedBody.AddTorque(worldTorque);
}
}
You can apply this as a separate behaviour to the object with the hinge joint, or you can take bits of it and incorporate them into your behaviour.
This code assumes the hinge joint has a connected rigidbody that it is rubbing against, if that is not the case, simply remove the lines that refer to the _connectedRigidbody.