NavMesh Agent override rotation - c#

I have enemies that patrol to different waypoints using NavMesh Agent I want when the enemy reach the next waypoint to have the same rotation as that waypoint.
Here is the code:
void Update ()
{
if (agent.remainingDistance < 0.1)
{
// tried to stop the agent so I can override it's rotation, doesn't work
agent.Stop();
// Give him the desired rotation
transform.rotation = wayPoints[curretPoint].rotation;
if (curretPoint < wayPoints.Length -1)
{
curretPoint++;
}
else
{
curretPoint = 0;
}
// make him wait for a fixed amount of time
patrolTimer += Time.deltaTime;
if (patrolTimer >= patrolWait)
{
patrolTimer = 0;
agent.SetDestination (wayPoints[curretPoint].position);
agent.Resume ();
}
}
}
The problem is that he keeps rotating back and forth very quickly, I can't get teh desired effect that I want.

Try setting Angular Speed of NavMesh Agent to 0.
Edit:
That should work:
// make him wait for a fixed amount of time
patrolTimer += Time.deltaTime;
if (patrolTimer >= patrolWait)
{
if (curretPoint < wayPoints.Length -1)
{
curretPoint++;
}
else
{
curretPoint = 0;
}
patrolTimer = 0;
agent.SetDestination (wayPoints[curretPoint].position);
agent.Resume ();
}

This is how I handled it:
Instead of doing agent.Stop(); and agent.Resume(); I simply set its speed to 0 and used transform.Rotate to rotate the character.

Related

How to Check the time a player is below a y-Coordinate in C#

I want my script to check how long the player is below a given y coordinate. However, since I am checking for the information inside a FixedUpdate void I cannot directly add a while loop. therefore, I tried the following:
void FixedUpdate()
{
if(rb.position.y < 1f)
{
checkIfLost();
}
}
IEnumerator checkIfLost()
{
while(rb.position.y < 1f)
{
float timeGiven = 5 - Time.deltaTime;
if(timeGiven <= 0)
{
FindObjectOfType<GameManager>().EndGame();
}
yield return null;
}
}
This does not work.
I am new to unity C#, and I have tried searching it online but could not find anything.
What is a better alternative for running the while loop and checking how long the player is below a y-coordinate?
Just set a float variable as counter
private float timer = 0f;
void FixedUpdate()
{
if(rb.position.y < 1f)
{
timer +=Time.fixedDeltaTime;
if (timer > 5f)
{
//do something
FindObjectOfType<GameManager>().EndGame();
}
}
else
{
timer = 0f;
}
}
if you want to do that in Update (better) just replace timer +=Time.DeltaTime;

Player don't move slowly ( smoothly)

I have a question please in my game when i write "LEFT" in a InputField and click on a UI Button the cube move "LEFT" and eat coins(the same for up, down , right) my problem is when i wrote this code below the player moved but not slowly more like disappear than appear in the position that declare it
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GameManager : MonoBehaviour
{
public InputField mainInputField;
//public float speed;
public GameObject Player;
public Button Click_me;
public float smoothing = 1f;
public Transform TargetRight1;
public Transform TargetRight2;
public Transform TargetUP;
// Start is called before the first frame update
void Start()
{
}
public void SubmitName()
{
string[] lines = mainInputField.text.Split('\n');
for (int i = 0; i < lines.Length; i++)
{
if (lines[i] == "UP")
{
// moveUP();
StartCoroutine(MyCoroutineUP(TargetUP));
}
else if (lines[i] == "DOWN")
{
//MoveDown();
}
else if (lines[i] == "LEFT")
{
//MoveLeft();
}
else if (lines[i] == "RIGHT")
{
StartCoroutine(MyCoroutineUP(TargetRight1));
}
}
// Click_me.interactable = false;
}
IEnumerator MyCoroutineUP(Transform target)
{
while (Vector3.Distance(Player.transform.position, target.position) > 0.05f)
{
Player.transform.position = Vector3.Lerp(Player.transform.position, target.position, smoothing * Time.deltaTime);
}
yield return null;
}
}
know if i put the yield return null; inside the while loop like this
while (Vector3.Distance(Player.transform.position, target.position) > 0.05f)
{
Player.transform.position = Vector3.Lerp(Player.transform.position, target.position, smoothing * Time.deltaTime);
yield return null;
}
the player move slowly and get the coins but if i have more than 2 ligne for example i wrote LEFT , UP the while loop won't work properly when i call the function in the first line. sorry for my English
You will get concurrent Coroutines.
It sounds like what you actually are asking is how to stack multiple commands and work them one by one. This gets a bit more complex but sounds like the perfect usecase for a Queue
private readonly Queue<Transform> _commands = new Queue<Transform>();
public void SubmitName()
{
var lines = mainInputField.text.Split('\n');
mainInputField.text = "";
foreach (var line in lines)
{
switch (line)
{
case "UP":
// adds a new item to the end of the Queue
_commands.Enqueue(TargetUp);
break;
case "DOWN":
_commands.Enqueue(TargetDown);
break;
case "LEFT":
_commands.Enqueue(TargetLeft);
break;
case "RIGHT":
_commands.Enqueue(TargetRight);
break;
}
}
StartCoroutine(WorkCommands());
}
private IEnumerator WorkCommands()
{
// block input
Click_me.interactable = false;
// run this routine until all commands are handled
while (_commands.Count > 0)
{
// returns the first element and at the same time removes it from the queue
var target = _commands.Dequeue();
// you can simply yield another IEnumerator
// this makes it execute and at the same time waits until it finishes
yield return MovementCoroutine(target);
}
// when done allow input again
Click_me.interactable = true;
}
To the lerping itself:
I wouldn't lerp like that. That starts the movement very quick and gets slower in the end but never really reaches the target position. If thats what you want leave it but I would rather recommend doing something like
private IEnumerator MovementCoroutine(Transform target)
{
var startPos = transform.position;
var targetPos = target.position;
var timePassed = 0f;
do
{
var lerpFactor = Mathf.SmoothStep(0, 1, timePassed / smoothing);
transform.position = Vector3.Lerp(startPos, targetPos, lerpFactor);
timePassed += Time.deltaTime;
yield return null;
}
while(timePassed < smoothing);
// just to be sure there is no over or undershooting
// in the end set the correct target position
transform.position = targetPos;
}
In smoothing you would then instead set the time in seconds the lerping should take in total. In my opinion this gives you more control. The SmoothStep makes the movement still being eased in and out.
If you want you could additionally also take the current distance into account for always making the object move with more or less the same speed regardless how close or far the target position is by adding/changing
var distance = Vector3.Distance(startPos, targetPos);
var duration = smoothing * distance;
do
{
var lerpFactor = Mathf.SmoothStep(0, 1, timePassed / duration);
...
}
while (timePassed < duration);
now in smoothing you would rather set the time in seconds the object should need to move 1 Unity unit.
I don't know your exact setup for the targets ofcourse but this is how it would look like with targets attached to the player (so they move along with it)

Can anyone help me make a script that rotates towards a specific angle

I am working on a unity game and
I have a gameobject i need to constantly rotate towards a target angle
And it needs to take the shortest way there
I have tried to use lerp co-routines to add/subbtract it to the angle but when i use it to quickly it gets stuck in weird positions
Transform target;
float speed;
//The angle to constantly rotate torwards
float yRotation = 120f;
private int dick;
void Start()
{
}
void Update()
{
if (Input.GetKeyDown(KeyCode.D))
{
if (dick < 3)
{
dick += 1;
}
else
{
dick = 1;
}
}
else if (Input.GetKeyDown(KeyCode.A))
{
if (dick >0 )
{
dick -= 1;
}
else
{
dick = 3;
}
}
if (dick == 1)
{
yRotation = 0;
}
else if (dick == 2)
{
yRotation = 120;
}
else if (dick == 3)
{
yRotation = 240;
}
As you might see there is some parts from the old code
The reason i use this kind of gear system is so that it cant get stuck in weird positions but i am not sure how to constantly rotate it to that target angle
Two things you can try :
In the Update, every time calculate the direction between you and the target, then calcultate the Angle, and then use Quaternion.AngleAxis() or simply Quaternion.RotateTowards()
You can also simply use Transform.LookAt(yourTarger.transform)

Not cycling through an array as expected

I'm trying to get the player to continue on after he jumps (see code), but what he does is return back to the jumpPosition transform without continuing on to the next point.
Here is what it is doing in Unity:
...
Here is my code for playerMovment:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class MovementController : MonoBehaviour
{
// public GameObject playerToMove; // not sure why I need this
public float moveSpeed; // move speed of the player going from player postion to current point, possible to use somewhere else
private Transform currentPoint; // used to determine where the next point the player has to move by cycling through 'points' array
public Transform jumpPoint; // used as a location trigger to tell the player when to jump -- will be attempting to make into an array
public Transform crouchPoint; // used as a location trigger to tell the player when to crounch -- will be attempting to make into an array
public Transform[] points; // an array of location for the 'currentPoint' to cycle through
public float maxPause = 100; // used to determine the length of time between when the player arrives at the 'currentPoint' and when to leave said point; default = 100
public float reducedPause = 2; // used to set 'maxPause' to a smaller number so that player won't keep jumping/crouching
public TestCharacterController2D controller; // acceses the TestCharacterController2D script (I didnt write this script but plan to modiify) used for basic move, jump, and crouch funtions
public Animator animator; // my attempt to find the player's animator
public bool isRight; // used to to determine which way the character is facing -- I think this can be accesed through the 'controller' variable (TestCharacterController2D script)
private bool jump; // to tell the 'controller' when to jump
private bool crouch; // to tell the 'controller' when to crouch
private bool pause = false; // used to determine when the player arrives at the 'currentPoint' and the 'maxPause' countdown begins
public int pointsSelection; // used to cycle the 'points' array when maxPause cycle is over and player is at current point
// public float jumpHeight = 100f; // not sure why used
void Start() // looking into 'onAwake' maybe? (or others)
{
currentPoint = points[pointsSelection]; // sets currentPoint to default location ('pointSelection' is 'publc' so can be modified in Unity
isRight = true; // player starts facing right -- as per character animations
}
void Update() // not sure if should have more in 'FixedUpdate' or others (maybe?)
{
jump = false;
if (Vector2.Distance(transform.position, currentPoint.position) < 0.05f)
// checks to see if player is at 'currentPoint'
{
pause = true; // starts the pause sequenece
Debug.Log("Pause = " + pause);
if (pause) // when the movement is pause do the the following
{
moveSpeed = 0;
animator.SetFloat("Speed", 0); // player stops moving -- works!
if (maxPause <= 100) // checks to see if still paused
{
Debug.Log("this is maxPause: " + maxPause);
if (maxPause < 0) // found 'maxPause' was going to far below zero
maxPause = 0;
maxPause--; // reduce pause amount (working way out of loop)
}
if (maxPause == 0) // when 'maxPause' timer has finished
{
pointsSelection++; // move to next point
maxPause = 100; // reset 'maxPause' timer
pause = false; // resume 'transform.position == currentPoint.position' process
}
}
if (pointsSelection == points.Length) // makes sure 'pointsSelection' doesn't go out of bounds
{
Debug.Log("at end of array");
pointsSelection = 0; // start the player's movement process over again
}
}
else // not sure if requried
{
Debug.Log("pause = false");
Debug.Log("this is the moveSpeed " + moveSpeed);
Debug.Log("pointsSelection: " + pointsSelection);
}
if (Vector2.Distance(transform.position, jumpPoint.position) < 0.05f && jumpPoint == currentPoint) // conditions for the jump action (automatic) -- I fell the whole thing needs to be more elaborate ** WORK IN PROGRESS **
{
jump = true;
}
else
jump = false;
currentPoint = points[pointsSelection]; // moved to line 130 -- not sure if better here
}
void FixedUpdate()
{
if (isRight && transform.position.x > currentPoint.position.x) // flipping the character -- I'm pretty sure I can use TestCharacterController2D to do this for me, this is comparing the player's 'transform'
{
moveSpeed = -0.25f; // tells controller to head in the left direction
isRight = false; // no longer facing right
}
if (!isRight && transform.position.x < currentPoint.position.x) // reverse of above
{
moveSpeed = 0.25f; // tells controller to head in the right direction
isRight = true; // no longer facing left
}
if (moveSpeed > 0 || moveSpeed < 0)
animator.SetFloat("Speed", 1); // player starts PlayerRun animation -- works!
// Move our character
controller.Move(moveSpeed, crouch, jump); // draws from the TestCharacterController2D script
}
public void OnLanding()
{
animator.SetBool("Jumped", false);
}
}

Lifetime = -1; does not effect Unity particles

I found a lot of topics saying that if I would like to remove a specific particle, I simply have to set it's LifeTime to -1.
I know my loop is working correctly, as the movement of each particle goes as planned AND I can see the "remove particle" Debug line in my log the moment it reaches it's destination. Did anything change over time, or am I missing something simple?
I'm using Unity 5,4,3f1 Personal
void Update ()
{
if(Input.GetKeyDown(KeyCode.Space)) PlayParticleEffect();
if (particleSystem != null) {
particles = new ParticleSystem.Particle[particleSystem.particleCount];
int count = particleSystem.GetParticles (particles);
for (int i = 0; i < count; i++) {
ParticleSystem.Particle particle = particles [i];
float dist = Vector3.Distance (particleTarget.transform.position, particle.position);
if (dist > 0.1f) {
particle.position = Vector3.MoveTowards (particle.position, particleTarget.transform.position, Time.deltaTime * 10);
particles [i] = particle;
} else {
particle.lifetime = -0;
Debug.Log ("remove particle");
}
}
particleSystem.SetParticles (particles, count);
}
}
You just need to set the remaining lifetime of the particle to 0 (if it's set to 0, the particle will disappear).
Your code doesn't work because you forgot to add particles [i] = particle; in the else branch of your if, you're never setting the lifetime to 0 to the actual particle:
if (dist > 0.1f) {
particle.position = Vector3.MoveTowards (particle.position, Vector3.zero, Time.deltaTime * 10);
particles [i] = particle;
} else {
particle.remainingLifetime = 0;
particles [i] = particle;
}
P.S.: I used remainingLifetime instead of lifetime since I'm on Unity 5.5

Categories