This question already has answers here:
Rotate GameObject over time
(2 answers)
Closed 5 years ago.
in my project i have a bridge at the moment when i colide with the bridge it rotates and don't stop rotate, what i want is to rotate that bridge trough a specific point and stop rotate, that bridge is inside a gameobject that is my pivotPoint in general i rotate the pivotPoint not the bridge, so i did this:
using UnityEngine;
using System.Collections;
public class fallBridge : MonoBehaviour {
private Rigidbody ball;
public GameObject bridgePivot;
private bool colided;
private bool rotating = true;
// Update is called once per frame
void Start(){
colided = false;
}
void Update () {
if (colided) {
if (rotating) {
Vector3 to = new Vector3 (0, 0, -85);
if (Vector3.Distance (bridgePivot.transform.eulerAngles, to) > 0.01f) {
bridgePivot.transform.eulerAngles = Vector3.Lerp (bridgePivot.transform.rotation.eulerAngles, to, Time.deltaTime);
} else {
bridgePivot.transform.eulerAngles = to;
rotating = false;
}
}
}
}
void OnCollisionEnter(Collision other)
{
ball = GameObject.FindWithTag ("Player").GetComponent<Rigidbody> ();
if (other.gameObject.tag == "Player" && ball.transform.localScale == new Vector3(2.0f,2.0f,2.0f)) {
Debug.Log("ENTER");
colided = true;
}
}
}
what am i doing wrong?? the colision detection works perfectly but on the update method it never stops rotate :S
You should do this with coroutine. Call the coroutine function and pass in the GameOjbect to rotate and the angle to rotate to when OnCollisionEnter is called. You can read how this function work here.
Te example below will rotate the GameObject -85 degree in z-axis within 3 seconds.
You can change that to whatever suits you.
public class fallBridge : MonoBehaviour
{
private Rigidbody ball;
public GameObject bridgePivot;
bool rotating = false;
void OnCollisionEnter(Collision other)
{
ball = GameObject.FindWithTag("Player").GetComponent<Rigidbody>();
if (other.gameObject.CompareTag("Player") && ball.transform.localScale == new Vector3(2.0f, 2.0f, 2.0f))
{
Debug.Log("ENTER");
Vector3 rotationAngle = new Vector3(0, 0, -85);
StartCoroutine(RotateObject(bridgePivot, rotationAngle, 3f));
}
}
IEnumerator RotateObject(GameObject gameObjectToMove, Vector3 eulerAngles, float duration)
{
if (rotating)
{
yield break;
}
rotating = true;
Vector3 newRot = gameObjectToMove.transform.eulerAngles + eulerAngles;
Vector3 currentRot = gameObjectToMove.transform.eulerAngles;
float counter = 0;
while (counter < duration)
{
counter += Time.deltaTime;
gameObjectToMove.transform.eulerAngles = Vector3.Lerp(currentRot, newRot, counter / duration);
yield return null;
}
rotating = false;
}
The error is in this line:
bridgePivot.transform.eulerAngles = Vector3.Lerp (bridgePivot.transform.rotation.eulerAngles, to, Time.deltaTime);
When you use Lerp you typically have a fixed beginning and end, and you make the last parameter (t) go from 0 to 1. In your case the endpoint is fixed, the t parameters is fixed also and you vary your start. This means that each update you take a small step towards your goal, but this step is a percentage of the way. So each update you come closer, and your next step will be smaller.
What you should do is remember where you were when you started, and at what time you started. You also need to define a speed for your bridge. Then you can move the bridge from start to end and you get control over the speed.
public class fallBridge : MonoBehaviour {
private Rigidbody ball;
public GameObject bridgePivot;
public float rotateDuration = 2; // Time in seconds
// When you begin rotating you fill these three variables
private float startTime;
private Vector3 from;
private bool rotating = false;
// If the target doesn't change you might as well define it beforehand
private Vector3 to = new Vector3 (0, 0, -85);
void Update () {
if (rotating) {
float t = (Time.time - startTime) / rotateDuration;
if (t < 1) {
bridgePivot.transform.eulerAngles = Vector3.Lerp (from, to, t);
} else {
bridgePivot.transform.eulerAngles = to;
rotating = false;
}
}
}
void OnCollisionEnter(Collision other)
{
ball = GameObject.FindWithTag ("Player").GetComponent<Rigidbody> ();
if (other.gameObject.tag == "Player" && ball.transform.localScale == new Vector3(2.0f,2.0f,2.0f)) {
Debug.Log("ENTER");
startTime = Time.time; // Begin now
from = bridgePivot.transform.eulerAngles; // Remember the start position
rotating = true; // Signal to start rotating
}
}
}
Related
Context
So I'm making a clone of Crossy Roads where the camera follows the player. It does some linear interpolation (Lerp) after moving, and the camera starts moving away from the player in the positive direction (x-axis until camera reaches to a certain range where player is not visible enough). Things I have tried is by flagging it, but I think I'm doing it wrong.
Problem
I have done my camera movements accordingly, but I am having an issue where the conditions are not properly met. I'm get the offset camera after not moving, but it does not the Lerp, and vice-versa. I want both to happen after a certain condition after the game starts. When the player moves, the camera follows it in Lerp. However, once the player is "Idle", its still Lerping. I want the camera to continue by itself and at the same time focus at the player's object.
Example
Camera with Lerp, but not moving away from the player
Camera moving away, but not following player with lerp
Code
CameraController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/*
** Camera following player (Smoothing and angle): https://youtu.be/4HpC--2iowE
** Maximo: https://www.youtube.com/watch?v=bXNFxQpp2qk&ab_channel=iHeartGameDev
** Moving character relative to camera: https://forum.unity.com/threads/moving-character-relative-to-camera.383086/
** Camera follow v2: https://youtu.be/Jpqt2gRHXtc?list=PLq_nO-RwB516fNlRBce0GbtJSfysAjOgU
*/
public class CameraController : MonoBehaviour
{
public GameObject player;
public PlayerControl playerControlScript;
private Vector3 newCameraPos;
public bool stillIdle;
void Start()
{
stillIdle = false;
PlayerControl playerControlScript = GetComponent<PlayerControl>();
}
void LateUpdate()
{
player = GameObject.FindGameObjectWithTag("Player");
if (playerControlScript.GetfirstInput()) //True
{
stillIdle = true;
newCameraPos = Vector3.Lerp(transform.position, playerControlScript.transform.position, Time.deltaTime);
transform.position = new Vector3(newCameraPos.x, 1, newCameraPos.z);
}
if (stillIdle)
transform.position = new Vector3(transform.position.x + 0.69f * Time.deltaTime, transform.position.y, transform.position.z); //Moving camera away effect
}
}
PlayerControl.cs
public class PlayerControl : MonoBehaviour
{
bool firstInput;
Vector3 startPos;
Vector3 endPos;
public bool GetfirstInput() //I was learning how to have a Get function while my member was private from another script file
{
return firstInput;
}
void Update()
{
if (Input.GetButtonDown("up") || Input.GetButtonDown("left") || Input.GetButtonDown("right") || Input.GetButtonDown("down"))
{
//if game starts
{
//Other variables being initialized here
firstInput = true;
}
}
}
}
Hierarchy/Inspector
Main Camera
Player Object
Some help would be appreciate it. I feel I have been staring at this problem and I bet it is something minimal and small from just thinking it.
Let me know if you need clarifications. I'm happy to edit and answer them for everyone
If player in your game does not change, you don't have to find the player reference in each LateUpdate().
I notice that once stillIdle is set true, it never goes back to false, is this your intention to do that?
You call Lerp when playerControlScript.GetfirstInput() is true, so maybe we need to look at its implementation. Maybe it turns true in some conditions you do not intend it to.
Maybe Try this
public class PlayerControl : MonoBehaviour
{
private bool _hasFireFirstInput = false;
private bool _isIdle = true;
public bool IsIdle => _isIdle;
public bool HasFireFirstInput => _hasFireFirstInput;
private void Update()
{
if (Input.GetButton("Horizontal") || Input.GetButton("Vertical"))
{
_hasFireFirstInput = true;
_isIdle = false;
Vector3 pos = transform.position;
pos = new Vector3(pos.x, pos.y, pos.z + .2f * Time.deltaTime);
transform.position = pos;
}
else
{
_isIdle = true;
}
}
}
I use Input.GetButton() rather than Input.GetButtonDown(), since the later only return true at the frame the button is pressed, meaning that if i long-press the button, it will return false after the next frame.
public class CameraController : MonoBehaviour
{
[SerializeField] PlayerControl _playerControlScript;
[SerializeField] Vector3 _offset;
[SerializeField] float _lerpSpeed;
bool _iskeepLerping = false;
float _lerpVal = 0f;
private void LateUpdate()
{
if (!_playerControlScript.HasFireFirstInput)
{
return;
}
if (_playerControlScript.IsIdle)
{
MoveAway();
}
else
{
Lerp();
}
}
private void MoveAway()
{
_iskeepLerping = false;
transform.position = new Vector3(transform.position.x + 0.69f * Time.deltaTime, transform.position.y, transform.position.z);
}
private void Lerp()
{
if (!_iskeepLerping)
{
_lerpVal = 0f;
}
Vector3 newCameraPos = Vector3.Lerp(transform.position, _playerControlScript.transform.position + _offset, _lerpVal);
transform.position = newCameraPos;
_lerpVal += _lerpSpeed * Time.deltaTime;
_iskeepLerping = true;
}
}
Hello everyone and thanks in advance for your answers!
I am a beginner in unity, coding my second game after i finshed a couple of tutorials.
Since today, i noticed that suddenly all my "GameObjects" have a "UnityEngine." in front of them.
I have no idea how that happened, and it is also not just in one script, but all of them. Heres an example of it:
UnityEngine.GameObject item = (UnityEngine.GameObject)Instantiate(itemGOList[i], spawnTransform, spawnRotation);
This worked fine before without the "UnityEngine.", but now it only works when its written this way.
Do you know how this could have happened and how to revert it?
This is one of the scripts:
using UnityEngine;
using UnityEngine.EventSystems;
public class Turret : MonoBehaviour
{
private Transform target;
private Enemy targetEnemy;
[Header("General")]
public float range = 10f;
[Header("Use Bullets/missiles (default)")]
public UnityEngine.GameObject bulletPrefab;
public float fireRate = 1f;
private float fireCountdown = 0f;
public AudioClip shootingSound;
private AudioSource audioSource;
[Header("Use Laser (default)")]
public bool useLaser = false;
public int damageOverTime = 20;
public float slowAmount = .5f;
public LineRenderer lineRenderer;
public ParticleSystem impactEffect;
public Light impactLight;
[Header("Unity Setup Fields")]
public string enemyTag = "Enemy";
public Transform partToRotate;
public float turnSpeed = 10f;
public Transform firePoint;
void Start()
{
InvokeRepeating(nameof(UpdateTarget), 0f, 0.3f); // Call the UpdateTarget Method after 0 seconds, then repeat every 0.3 seconds.
audioSource = GetComponent<AudioSource>(); //Puts the AudioSource of this GO (the turret) into the variable audioSource.
}
void UpdateTarget ()
{
UnityEngine.GameObject[] enemies = UnityEngine.GameObject.FindGameObjectsWithTag(enemyTag); // Find all enemies (and store in a list?).
float shortestDistance = Mathf.Infinity; // Create a float for the shortest distance to an enemy.
UnityEngine.GameObject nearestEnemy = null; // Create a variable which stores the nearest enemy as a gameobject.
foreach (UnityEngine.GameObject enemy in enemies) // Loop through the enemies array.
{
float distanceToEnemy = Vector3.Distance(transform.position, enemy.transform.position); //Get the distance to each enemy and stores it.
if (distanceToEnemy < shortestDistance) // If any of the enemies is closer than the original, make this distance the new shortestDistance and the new enemy to the nearestEnemy.
{
shortestDistance = distanceToEnemy;
nearestEnemy = enemy;
}
}
if (nearestEnemy != null && shortestDistance <= range) // Sets the target to the nearestEnemy (only if its in range and not null).
{
target = nearestEnemy.transform;
targetEnemy = nearestEnemy.GetComponent<Enemy>();
}
else
{
target = null;
}
}
void Update()
{
if (target == null) // If there is no target, do nothing.
{
if (useLaser)
{
if (lineRenderer.enabled)
{
lineRenderer.enabled = false;
impactEffect.Stop();
impactLight.enabled = false;
audioSource.Stop();
}
}
return;
}
LockOnTarget();
if (useLaser)
{
Laser();
}
else
{
if (fireCountdown <= 0f)
{
Shoot();
fireCountdown = 1f / fireRate;
}
fireCountdown -= Time.deltaTime;
}
}
void Laser()
{
targetEnemy.TakeDamage(damageOverTime * Time.deltaTime);
targetEnemy.Slow(slowAmount);
if (!lineRenderer.enabled)
{
lineRenderer.enabled = true;
impactEffect.Play();
impactLight.enabled = true;
if (audioSource.isPlaying == false)
{
audioSource.Play();
}
}
lineRenderer.SetPosition(0, firePoint.position);
lineRenderer.SetPosition(1, target.position);
Vector3 dir = firePoint.position - target.position;
impactEffect.transform.position = target.position + dir.normalized * 1f;
impactEffect.transform.rotation = Quaternion.LookRotation(dir);
}
void LockOnTarget()
{
Vector3 dir = target.position - transform.position; // Store the direction from turret to target.
Quaternion lookRotation = Quaternion.LookRotation(dir); // I have no idea how this works...
Vector3 rotation = Quaternion.Lerp(partToRotate.rotation, lookRotation, Time.deltaTime * turnSpeed).eulerAngles; // Convert quaternion angles to euler angles and Lerp it (smoothing out the transition).
partToRotate.rotation = Quaternion.Euler(0f, rotation.y, 0f); // Only rotate around the y-axis.
}
void Shoot()
{
UnityEngine.GameObject bulletGO = (UnityEngine.GameObject)Instantiate(bulletPrefab, firePoint.position, firePoint.rotation); // Spawn a bullet at the location and rotation of firePoint. (Also makes this a GO to reference it.
Bullet bullet = bulletGO.GetComponent<Bullet>(); // I have no idea how this works...
audioSource.PlayOneShot(shootingSound, 0.2f);
if (bullet != null) // If there is a bullet, use the seek method from the bullet script.
{
bullet.Seek(target);
}
}
void OnDrawGizmosSelected() // Do this method if gizmo is selected.
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, range); // Draw a wire sphere on the selected point (selected turret f. e.) and give it the towers range.
}
}
The problem was that i had a script called "GameObject" in my Unity Project.
I was also able to rename all "UnityEngine.GameObject" to "Gameobject" by using the Quick Action in Visual Studio.
Hey Guys I've been having a problem lately that I cant seem to solve.
A sprite is supposed to roam around (as it does) while nothing is inside its radius, however if the player moves close to it the sprite should theoretically move towards it and stop roaming.
The sprite doesn't follow the player and cant even see its tag since I cant even see the contents of the "Collider2D[] hits".
using System.Collections.Generic;
using UnityEngine;
public class FireCultist : MonoBehaviour
{
public float moveTimeSeconds; //Time it will take object to move, in seconds.
private float xMax = 10.0f; // The boundaries of the spawn area
private float yMax = 10.0f;
private float xMin = -10.0f; // The boundaries of the spawn area
private float yMin = -10.0f;
public int xDistanceRange; // The max distance you can move at one time
public int yDistanceRange;
private BoxCollider2D boxCollider; //The BoxCollider2D component attached to this object.
private Rigidbody2D rb2D; //The Rigidbody2D component attached to this object.
private float inverseMoveTime; //Used to make movement more efficient.
public Vector2 start;
public Vector2 end;
public bool roam = true;
public Collider2D[] hits;
void Start()
{
boxCollider = GetComponent<BoxCollider2D>();
rb2D = GetComponent<Rigidbody2D>();
inverseMoveTime = 1f / moveTimeSeconds;
InvokeRepeating("RandomMove", 0.0f, 5.0f);
}
void Update()
{
Collider2D[] hits = Physics2D.OverlapCircleAll(transform.position, 10); // returns all colliders within radius of enemy
int i = 0;
while(hits.Length > i)
{
Debug.Log("Sees");
Debug.Log(hits[i]);
i++;
}
followPlayer();
if (roam)
{
Debug.Log("Roam");
transform.position = Vector2.MoveTowards(transform.position, end, inverseMoveTime * Time.deltaTime); //Random move to new position
}
}
public void followPlayer()
{
foreach (Collider2D hit in hits)
{
if (hit.tag == "Player") // if the player is within a radius
{
Debug.Log("Chasing Player");
transform.position = Vector2.MoveTowards(transform.position, GameObject.Find("Prefabs/Player").GetComponent<Transform>().position, inverseMoveTime * Time.deltaTime); // chase player
roam = false;
}
else
{
Debug.Log("Continues");
roam = true; // Continue RandomMove()
}
}
}
public void RandomMove() // gets random coordinates near enemy and moves there
{
float xDistance = Random.Range(-xDistanceRange, xDistanceRange); // check
float yDistance = Random.Range(-yDistanceRange, yDistanceRange);// check
if (xDistance < xMax && xDistance > xMin && yDistance < yMax && yDistance > yMin && roam == true) // If within boundaries of walking space
{
start = transform.position;
end = start + new Vector2(xDistance, yDistance);
Debug.Log("Roaming From : " + start + " To : " + end);
}
}
}
The roaming algorithm works however not too sure about the tag detection.
The script belongs to this enemy object
Player Object Properties
It looks like you are declaring a new hits variable during every update instead of using your class-level variable. This means the variable inside of followPlayer() will never be instantiated, and the information will not be passed between the two methods.
Try this:
void Update()
{
hits = Physics2D.OverlapCircleAll(transform.position, 10);
//...
}
You might also consider attaching a trigger collider to the enemy which sends a notification when the player enters/exits the trigger instead of relying on OverlapCircleAll()
void OnTriggerEnter2D(Collider2D col)
{
if(col.gameObject.tag == "Player"){
roam = false;
}
}
void OnTriggerExit2D(Collider2D col)
{
if(col.gameObject.tag == "Player"){
roam = true;
}
}
When the game starts, a random waypoint is selected from an array. The camera should then rotate to face the selected random waypoint and start moving towards it.
Once the camera has reached the waypoint, it should wait 3 seconds before rotating to face and move towards the next random waypoint.
The problem I have is in Start(). The camera does not rotate to face the first waypoint before it starts moving towards it. Instead, it moves towards the first waypoint backwards. Then, when it reaches the waypoint, it waits 3 seconds to rotate and move towards the next waypoint.
It's working fine except that the camera does not rotate to face the first selected random waypoint. It's moving to it backward without first rotating to face it.
Here's my code:
The waypoints script
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Waypoints : MonoBehaviour
{
public GameObject[] waypoints;
public GameObject player;
public float speed = 5;
public float WPradius = 1;
public LookAtCamera lookAtCam;
private int current = 0;
private bool rot = false;
public void Init()
{
waypoints = GameObject.FindGameObjectsWithTag("Target");
if(waypoints.Length > 0)
{
StartCoroutine(RotateFacingTarget(waypoints[UnityEngine.Random.Range(0, waypoints.Length)].transform));
}
}
void Update()
{
if (waypoints.Length > 0)
{
if (Vector3.Distance(waypoints[current].transform.position, transform.position) < WPradius)
{
current = UnityEngine.Random.Range(0, waypoints.Length);
rot = false;
StartCoroutine(RotateFacingTarget(waypoints[current].transform));
if (current >= waypoints.Length)
{
current = 0;
}
}
if (rot)
transform.position = Vector3.MoveTowards(transform.position, waypoints[current].transform.position, Time.deltaTime * speed);
}
}
IEnumerator RotateFacingTarget(Transform target)
{
yield return new WaitForSeconds(3);
lookAtCam.target = target;
rot = true;
}
}
The look at camera script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LookAtCamera : MonoBehaviour
{
//values that will be set in the Inspector
public Transform target;
public float RotationSpeed;
//values for internal use
private Quaternion _lookRotation;
private Vector3 _direction;
// Update is called once per frame
void Update()
{
//find the vector pointing from our position to the target
if (target)
{
_direction = (target.position - transform.position).normalized;
//create the rotation we need to be in to look at the target
_lookRotation = Quaternion.LookRotation(_direction);
//rotate us over time according to speed until we are in the required rotation
transform.rotation = Quaternion.Slerp(transform.rotation, _lookRotation, Time.deltaTime * RotationSpeed);
}
}
}
How can I fix this?
Let's assume that Waypoints.Init() is being called and your waypoints variable has an array of 3.
Waypoints.Init() starts a coroutine
Your coroutine waits 3 seconds
After 3 seconds, you set your camera target which Slerps to face the position
Update on its first frame says waypoints.Length > 0 == true
It's not close to its target, and rot is false, so it does not move
Now, you're waiting 3 seconds, not rotating, and not moving.
Your coroutine's 3 second wait time is up and starts the rotation toward your target
rot is now true at the start of your rotation, so your Update method starts moving toward the target as well
It would seem that your logic is off in how the order of operations works. If it needs to act as you describe, I suggest that you operate on the target differently.
I've implemented the following using an enum:
Waypoints
public class Waypoints : MonoBehaviour
{
private GameObject[] waypoints;
private Transform currentWaypoint;
private enum CameraState
{
StartRotating,
Rotating,
Moving,
Waiting
}
private CameraState cameraState;
public GameObject player;
public float speed = 5;
public float WPradius = 1;
public LookAtCamera lookAtCam;
private int current = 0;
private bool isCameraRotating = false;
void Start()
{
cameraState = CameraState.StartRotating;
}
void Update()
{
switch (cameraState)
{
// This state is used as a trigger to set the camera target and start rotation
case CameraState.StartRotating:
{
// Sanity check in case the waypoint array was set to length == 0 between states
if (waypoints.Length == 0)
break;
// Tell the camera to start rotating
currentWaypoint = waypoints[UnityEngine.Random.Range(0, waypoints.Length)].transform;
lookAtCam.target = currentWaypoint;
cameraState = CameraState.Rotating;
break;
}
// This state only needs to detect when the camera has completed rotation to start movement
case CameraState.Rotating:
{
if (lookAtCam.IsFinishedRotating)
cameraState = CameraState.StartMoving;
break;
}
case CameraState.Moving:
{
// Move
transform.position = Vector3.MoveTowards(transform.position, currentWaypoint.position, Time.deltaTime * speed);
// Check for the Waiting state
if (Vector3.Distance(currentWaypoint.position, transform.position) < WPradius)
{
// Set to waiting state
cameraState = CameraState.Waiting;
// Call the coroutine to wait once and not in CameraState.Waiting
// Coroutine will set the next state
StartCoroutine(WaitForTimer(3));
}
break;
}
case CameraState.Waiting:
// Do nothing. Timer has already started
break;
}
}
IEnumerator WaitForTimer(float timer)
{
yield return new WaitForSeconds(timer);
cameraState = CameraState.StartRotating;
}
public void RefreshWaypoints()
{
waypoints = GameObject.FindGameObjectsWithTag("Target");
}
}
LookAtCamera
public class LookAtCamera : MonoBehaviour
{
// Values that will be set in the Inspector
public Transform target;
public float RotationSpeed;
private float timer = 0.0f;
public bool IsRotationFinished
{
get { return timer > 0.99f; }
}
// Update is called once per frame
void Update()
{
if (target != null && timer < 0.99f)
{
// Rotate us over time according to speed until we are in the required rotation
transform.rotation = Quaternion.Slerp(transform.rotation,
Quaternion.LookRotation((target.position - transform.position).normalized),
timer);
timer += Time.deltaTime * RotationSpeed;
}
}
}
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class Waypoints : MonoBehaviour
{
public GameObject[] waypoints;
public Transform target;
public float moveSpeed = 10f;
public float slowDownSpeed = 3f;
public float reverseSlowDownSpeed = 3f;
public float rotationSpeed = 1f;
private int targetsIndex = 0;
private Vector3 originalPosition;
private GameObject[] players;
public Transform reverseTarget;
private int reverseTargetsIndex = 0;
private Vector3 reverseOriginalPosition;
public bool random = false;
public bool getNextRandom = true;
// Use this for initialization
void Start()
{
waypoints = GameObject.FindGameObjectsWithTag("Blocks");
players = GameObject.FindGameObjectsWithTag("Player");
originalPosition = players[0].transform.localPosition;
}
// Update is called once per frame
void Update()
{
if (random == true)
{
RandomWayPointsAI();
}
else
{
WayPointsAI();
}
}
private void WayPointsAI()
{
if (targetsIndex == waypoints.Length)
targetsIndex = 0;
target = waypoints[targetsIndex].transform;
if (MovePlayer())
targetsIndex++;
}
private void ReverseWayPointsAI()
{
if (reverseTargetsIndex == 0)
reverseTargetsIndex = waypoints.Length - 1;
reverseTarget = waypoints[reverseTargetsIndex].transform;
if (MovePlayer())
reverseTargetsIndex--;
}
void RandomWayPointsAI()
{
if (random == true && getNextRandom)
{
int index = UnityEngine.Random.Range(0, waypoints.Length);
target = waypoints[index].transform;
getNextRandom = false;
}
getNextRandom = MovePlayer();
}
bool MovePlayer()
{
float distance = Vector3.Distance(players[0].transform.position, target.transform.position);
players[0].transform.localRotation = Quaternion.Slerp(players[0].transform.localRotation, Quaternion.LookRotation(target.position - players[0].transform.localPosition), rotationSpeed * Time.deltaTime);
//move towards the player
if (distance < 30)
{
players[0].transform.localPosition += players[0].transform.forward * slowDownSpeed * Time.deltaTime;
}
else
{
players[0].transform.localPosition += players[0].transform.forward * moveSpeed * Time.deltaTime;
}
if (distance < target.transform.localScale.magnitude)
return true;
else
return false;
}
void DrawLinesInScene()
{
// draw lines between each checkpoint //
for (int i = 0; i < waypoints.Length - 1; i++)
{
Debug.DrawLine(waypoints[i].transform.position, waypoints[i + 1].transform.position, Color.blue);
}
// draw a line between the original transform start position
// and the current transform position //
Debug.DrawLine(originalPosition, players[0].transform.position, Color.red);
Debug.DrawLine(reverseOriginalPosition, players[1].transform.position, Color.red);
// draw a line between current transform position and the next waypoint target
// each time reached a waypoint.
if (target != null)
Debug.DrawLine(target.transform.position, players[0].transform.position, Color.green);
if (reverseTarget != null)
Debug.DrawLine(reverseTarget.transform.position, players[1].transform.position, Color.green);
}
void AddColliderToWaypoints()
{
foreach (GameObject go in waypoints)
{
SphereCollider sc = go.AddComponent<SphereCollider>() as SphereCollider;
sc.isTrigger = true;
}
}
}
There are two problems with the script.
If the Move Speed is set to 3 i need to set the Rotation Speed at least to the 10 if i will set the Rotation Speed to 3 or 4 or 5 the rotation will be too wide and it will take much time to the player to get back on track after rotating.
But if it's 10 it seems he is almost rotating on the place so it's not good either.
I want to be able to change the player rotation speed but also to keep him on the waypoints track at any time. I mean that each waypoint the player is reaching to that he will get to it's center. In this case cubes so not only to touch the waypoint but to get to it's center then moving to the next waypoint.
Another problem i see is with the RandomWayPointsAI()
When i change it to use the random method i'm not sure if it's just picking up random positions around the grid or if it's picking random blocks(Cubes).
But it's never getting to a cube it' getting close or between two or sometimes on a cube and same as before also on the random i want to make the random waypoints not just positions but blocks and to get to each random block center.
Center i mean like standing on it.
A glaring problem in the showcased code is the use of local positions and rotations. When moving and rotating characters and objects in the world you should use world space.
Localposition and localrotation are based on the position and rotation of the parent object. Using those to move your object across the world will cause weird problems.
I think the following answer has a pretty accurate explanation of that stuff https://teamtreehouse.com/community/global-space-vs-local-space