Issues with a script that should follow another GameObject's position - c#

I currently have a little issue with a script I made. Basically, I want to create a script that makes its GameObject (let's name it A) and follows another GameObject's (named B) position. I know a simple way to do that would be to parent A to B, but I'm not doing it for two reasons :
1) I want to be able to apply a smoothing (whose value I can change) on A's movement;
2) I want to be able to make A follow B's position and/or rotation at will.
Here is the script I wrote :
using UnityEngine;
using System.Collections;
public class FollowGameObject : MonoBehaviour {
public GameObject m_GameObjectToFollow;
public bool m_FollowPosition;
public bool m_FollowRotation;
public float m_PositionSmoothing;
public float m_RotationSmoothing;
// Should not be changed once set
public bool m_UseOffsetPosition;
public bool m_UseOffsetRotation;
private Vector3 m_PositionOffset;
private Quaternion m_RotationOffset;
void Start () {
m_PositionSmoothing = Mathf.Clamp(m_PositionSmoothing, 0.0f, 1.0f);
m_RotationSmoothing = Mathf.Clamp(m_RotationSmoothing, 0.0f, 1.0f);
if (m_UseOffsetPosition)
{
m_PositionOffset = transform.position - m_GameObjectToFollow.transform.position;
} else {
m_PositionOffset = Vector3.zero;
}
if (m_UseOffsetRotation)
{
m_RotationOffset = transform.rotation * Quaternion.Inverse(m_GameObjectToFollow.transform.rotation);
} else {
m_RotationOffset = Quaternion.identity;
}
}
void FixedUpdate () {
if (m_FollowPosition) {
Vector3 goalPosition = m_GameObjectToFollow.transform.position + m_PositionOffset;
transform.position = Vector3.Lerp(transform.position, goalPosition, m_PositionSmoothing);
//transform.Translate(newPosition - transform.position, Space.World);
}
if (m_FollowRotation) {
Quaternion goalRotation = m_GameObjectToFollow.transform.rotation * m_RotationOffset;
transform.rotation = Quaternion.Lerp(transform.rotation, goalRotation, m_RotationSmoothing);
}
}
I hope the code is easily understandable, if not feel free to ask.
In any case, once I attach this script to A and assign its m_GameObjectToFollow attribute to B (B is parented to a character controller, and I parented a sphere renderer to A so I can see if it follows B correctly), I notice that A is indeed following B, but I see that its position (through the sphere renderer) is "fluctuating" between the "right" position (B's) and another one. Visually, the sphere is flickering.
I tried putting the smoothing values to 1 (i.e. A should always be at B's position/rotation). I still see a flickering.
Could someone explain to me what I did wrong?
EDIT : Seems like I'm using Lerp the wrong way with its last value. I modified the script to use speed values instead of smoothing values, but still the same problem when I try to create some smooth movements (with lower speed values).
I have troubles explaining the problem properly. The best way to see what the problem look like would be to experience it yourself :
1) Create a scene with a terrain and a character controller in it;
2) Parent the main camera to the controller (so that it always follows it);
3) Create a new GameObject with a renderer (for example, a sphere), not parented to any other GameObject, but attach the following script to it :
using UnityEngine;
using System.Collections;
public class FollowGameObject : MonoBehaviour {
public GameObject m_GameObjectToFollow;
public bool m_FollowPosition;
public bool m_FollowRotation;
// Betzeen 0 and 1. 1 means that a complete unsmoothed follow
public float m_PositionFollowSpeed;
public float m_RotationFollowSpeed;
// Should not be changed once set
public bool m_UseOffsetPosition;
public bool m_UseOffsetRotation;
private Vector3 m_PositionOffset;
private Quaternion m_RotationOffset;
void Start () {
if (m_UseOffsetPosition)
{
m_PositionOffset = transform.position - m_GameObjectToFollow.transform.position;
} else {
m_PositionOffset = Vector3.zero;
}
if (m_UseOffsetRotation)
{
m_RotationOffset = transform.rotation * Quaternion.Inverse(m_GameObjectToFollow.transform.rotation);
} else {
m_RotationOffset = Quaternion.identity;
}
}
void Update () {
if (m_FollowPosition) {
Vector3 goalPosition = m_GameObjectToFollow.transform.position + m_PositionOffset;
transform.position = Vector3.Slerp(transform.position, goalPosition, Time.deltaTime * m_PositionFollowSpeed);
}
if (m_FollowRotation) {
Quaternion goalRotation = m_GameObjectToFollow.transform.rotation * m_RotationOffset;
transform.rotation = Quaternion.Slerp(transform.rotation, goalRotation, Time.deltaTime * m_RotationFollowSpeed);
}
}
}
With :
m_GameObjectToFollow = the character controller GameObject;
m_FollowPosition = true;
m_PositionFollowSpeed = 10;
(The other parameters values don't matter for this test)
Now start the scene and move the character controller, I will see the sphere flickering during motion, but if you stop moving it will smoothly go to the controller.

You are using FixedUpdate. Is there any special reason to do so?
Anyway, try to use Update or LateUpdate instead of FixedUpdate or check Fixed Timestep in Project Settings => Time.
Also read the answer to this question for more information about difference between Update and FixedUpdate.

Related

How do i get one object to track and move towards another object

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyControler : MonoBehaviour
{
private Transform player;
// Start is called before the first frame update
void Start()
{
//Note in this case we're saving the transform in a variable to work with later.
//We could save the player's game object (and just remove .transform from the below) but this is cleaner
var player = GameObject.FindWithTag("Player").transform;
}
// Update is called once per frame
void Update()
{
//**** The code below you need to modify and move into your own method and call that method from here.
//**** Don't overthink it. Look at how Start() is defined. Your own Move method would look the exact same.
//**** Experiment making it private void instead of public void. It should work the same.
//How much will we move by after 1 second? .5 meter
var step = .5f * Time.deltaTime; // 5 m/s
var newPosition = Vector3.MoveTowards(transform.position, player, step);//This is one way to move a game object by updating the transform. Watch the videos in this module and it should become apparent what goes here.
}
}
The transform does not map to the tagged player. I was trying to get an enemy in unity to move towards a moving player for a class, but I'm completely lost.
You had three issues in your code. The first was that you were defining a new player variable in the Start method. This hid the player member field you defined earlier.
The second issue was that you were getting a value to move towards, but you weren't assigning that value to the current objects position.
The third issue was that you were feeding in a Transform into the MoveTowards method, when you should have been feeding in a Vector2.
The code below should rectify these issues.
public class EnemyControler : MonoBehaviour
{
private Transform _player;
void Start()
{
_player = GameObject.FindWithTag("Player").transform;
}
void Update()
{
var step = .5f * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, _player.position, step);
}
}
Try doing something like this ive used this in the past to do something similar once you understand the code change it to what you desire
public int minRange;
private Transform target = null;
private void OnTriggerEnter(Collider other)
{
if (other.tag == "Player")
target = other.transform;
}
private void OnTriggerExit(Collider other)
{
if (other.tag == "Player")
target = null;
}
void update()
{
transform.LookAt(target);
float distance = Vector3.Distance(transform.position,
target.position);
bool tooClose = distance < minRange;
Vector3 direction = tooClose ? Vector3.back : Vector3.forward;
if (direction == Vector3.forward)
{
transform.Translate(direction * 6 * Time.deltaTime);
}
else
{
transform.Translate(direction * 3 * Time.deltaTime);
}
}

Struggling in Unity 3d object Controls

I'm totally new to Unity and game development...I made a 2D object of the car that can move to 8 directions....each direction with the specific animation of the car's movement...Now, how do I make my car move in such a way that if it's moving straight LEFT it shouldn't go immediately straight to RIGHT when turning RIGHT, so I want it to make a proper round turn or a "U TURN" to move towards its opposite direction and obviously the same with UP and DOWN turns....can anyone please help me in at least one way I can fix this?
or the other way to ask this question would be if I'm moving my object to x = -1 direction then on turning to x = 1 it should first go through x = 0 and then x = 1 so that it looks like a turn.
this is the code for my CAR so far..
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CARmovement : MonoBehaviour
{
public float speed;
private Rigidbody2D myRigidbody;
private Vector3 change;
private Animator animator;
private Vector3 lastMoveDirection;
// Start is called before the first frame update
void Start()
{
animator = GetComponent<Animator>();
myRigidbody = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
change = Vector3.zero;
change.x = Input.GetAxis("Horizontal");
change.y = Input.GetAxis("Vertical");
UpdateAnimationAndMove();
}
void UpdateAnimationAndMove()
{
if (change != Vector3.zero)
{
MoveCar();
animator.SetFloat("moveX", change.x);
animator.SetFloat("moveY", change.y);
animator.SetBool("driving", true);
}
else
{
animator.SetBool("driving", false);
}
}
void MoveCar()
{
myRigidbody.MovePosition(transform.position + change * speed * Time.deltaTime);
}
}
I try an example of rotating a car. We add an object (here I add a car as an example), select the object (car) to create a C# Script script, double-click to open, we define two variables Speed_move, Speed_rot to control the movement speed and Rotation speed and assign values to them. We use Translate to control the forward and backward movement of the cube through the W and S buttons, forward with forward, and back with back; use Rotate to control the rotation of the object through the A and D buttons, up is the Y-axis rotation. The following is the code for the specific rotation.
if (Input.GetKey(KeyCode.W))
{
this.transform.Translate(Vector3.forward * Time.deltaTime * Speed_move);
}
if (Input.GetKey(KeyCode.S))
{
this.transform.Translate(Vector3.back * Time.deltaTime * Speed_move);
}
if (Input.GetKey(KeyCode.A))
{
this.transform.Rotate(Vector3.up * Time.deltaTime * -Speed_rot);
}
if (Input.GetKey(KeyCode.D))
{
this.transform.Rotate(Vector3.up * Time.deltaTime * Speed_rot);
}

Unity "Unassigned Reference Exception"

I'm super new to coding and to this forum so forgive me if I break any taboo's here. I'm simply working on a 3rd person camera, just kind of messing around but I keep getting
UnassignedReferenceException: The variable CameraFollowObj of CameraFollow has not been assigned.
You probably need to assign the CameraFollowObj variable of the CameraFollow script in the inspector.
CameraFollow.CameraUpdater () (at Assets/Scripts/CameraFollow.cs:68)
CameraFollow.LateUpdate () (at Assets/Scripts/CameraFollow.cs:62)"
I've created an object for my camera to follow and placed it on the model. Then moved the object to what I believe to be the correct field but the issue still persists.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraFollow : MonoBehaviour
{
public float CameraMoveSpeed = 120.0f;
public GameObject CameraFollowObj;
Vector3 FollowPOS;
public float clampAngle = 80.0f;
public float InputSensitivity = 150.0f;
public GameObject CameraObj;
public GameObject PlayerObj;
public float camDistanecXToPlayer;
public float camDistanecYToPlayer;
public float camDistanecZToPlayer;
public float mouseX;
public float mouseY;
public float finalInputX;
public float finalInputZ;
public float smoothX;
public float smoothY;
private float rotY = 0.0f;
private float rotX = 0.0f;
// Start is called before the first frame update
void Start()
{
Vector3 rot = transform.localRotation.eulerAngles;
rotY = rot.y;
rotX = rot.x;
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
// Update is called once per frame
void Update()
{
float InputX = Input.GetAxis("RightStickHorizontal");
float InputZ = Input.GetAxis("RightStickVertical");
mouseX = Input.GetAxis("Mouse X");
mouseY = Input.GetAxis("Mouse Y");
finalInputX = InputX + mouseX;
finalInputZ = InputZ + mouseY;
rotY += finalInputX * InputSensitivity * Time.deltaTime;
rotX += finalInputZ * InputSensitivity * Time.deltaTime;
rotX = Mathf.Clamp(rotX, -clampAngle, clampAngle);
Quaternion localRotation = Quaternion.Euler(rotX, rotY, 0.0f);
transform.rotation = localRotation;
}
void LateUpdate()
{
CameraUpdater();
}
void CameraUpdater()
{
Transform target = CameraFollowObj.transform;
float step = CameraMoveSpeed * Time.deltaTime;
transform.position = Vector3.MoveTowards (transform.position, target.position, step);
}
}
Make sure you haven't added the script to another gameobject somewhere else in the project that might cause this error.
You can search for the script in the scene search bar and all the gameObjects with the script attached will appear. Also in runtime if you right click on the script and in the contextual menu you select option kind of "find all the references in the scene" or something similar, you get all the instances of the script in your scene.
I think you should have drargged the script into another gameObject by mistake where the cameraToFollow gameObject is empty so you get the unnasigned error.
Hope this helps.
There are multiple things you can try to do:
Make sure you dragged the correct object in the field (I doubt that your character object is called CameraFollow)
Make sure that you dragged in an object from the Hierarchy and not the Assets window (ethats means that you need to drag in objects that are currently in the scene and can be seen on the hierarchy)
If you try everything from above and it doesen't work try assigning the object in the start function of the script. You can use GameObject.Find
Hope this helped to clarify a few things for you. Now if you really want to create a top level camera system you can also check this video out. Its an example of how to make a third person camera with the Cinemachine component (comes with Unity package manager for free)
I wish you luck with coding in Unity and welcome to the community :)

How to rotate a GameObject more than once

trying to use suggested option have an error vector3 right is not in its definition
line transform.Rotate(Vector3.Right
thank you in advance
using UnityEngine;
using System.Collections;
public class ForwardBack : MonoBehaviour {
// speed variable
public float speed;
public KeyCode pressLeft;
public KeyCode pressRight;
public float rotationSpeed;
// Use this for initialization
void Start () {
speed = 1f;
}
// Update is called once per frame
void Update () {
transform.Translate(0f, speed*Input.GetAxis("Vertical") * Time.deltaTime,0f);
if (Input.GetKey(KeyCode.RightArrow))
{
transform.Rotate(Vector3.Right * rotationSpeed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.LeftArrow))
{
transform.Rotate(Vector3.Left * rotationSpeed * Time.deltaTime);
}
}
}
Try Input.GetKey instead of Input.GetKeyDown
Input.GetKeyDown detects if a button is pressed, whereas Input.GetKey checks for a continuous press. I imagine that is why your cylinder is only turning once.
There are quite a few inefficiencies in your code. You should not call GetComponent<>() in the Update loop. Instead store a referece to it using the Start function and use that in the Update loop:
public class ForwardBack : MonoBehaviour
{
private Transform thisTransform = null;
void Start ()
{
// Get refrence
thisTransform = GetComponent<Transform>();
}
void Update ()
{
//Use refrence.
thisTransform.Rotate(Vector3.right * Time.deltaTime);
}
}
Note: You might realise that every child of MonoBehaviour inherits the transform property which will look up a reference to the Transform component. Using this is inefficient. You should get your own reference like I have shown here.
Edit:As noted by #JoeBlow the transform property may be fine to use. There is nothing mentioned about how it returns the Transform component in the Unity docs. I have read that it is just a wrapper for GetComponent though from a few different sources. Use at your own discretion.
Secondly, don't use eulerAngles to rotate. It even says so in the docs.
Only use this variable to read and set the angles to absolute values. Don't increment them, as it will fail when the angle exceeds 360 degrees. Use Transform.Rotate instead.
It looks like you're not even incrementing the angle, just setting it to new Vector3(0, 0, -90) anyways which means even if you did do this it will just be set to that value rather than slowly increasing.
The docs for eulerAngles also lead you to what you should be using which is Transform.Rotate.To get this to work you will have to change the input method to Input.GetKeyrather than Input.GetKeyDown but this has already been mentioned in one of the other answers. Then you can rotate around your desired axis. Remember to use Time.deltaTime to scale the value so as it rotates at the same speed no matter what framerate you have. Your code for rotation might look something like this:
public class ForwardBack : MonoBehaviour
{
public float roatationSpeed;
private Transform thisTransform = null;
void Start ()
{
thisTransform = GetComponent<Transform>();
}
void Update ()
{
if(Input.GetKey(KeyCode.RightArrow)
{
thisTransform.Rotate(Vector3.right * rotationSpeed * Time.deltaTime);
}
if(Input.GetKey(KeyCode.LeftArrow)
{
thisTransform.Rotate(Vector3.left * rotationSpeed * Time.deltaTime);
}
}
}

Unity Game Engine Tutorial?

My game is a 2D RTS, and I was wondering if anyone knew of a good tutorial for Unity, or if someone well-versed in the syntax of it could tell me what I could have done wrong.
So, I have my camera object, and my player object, both tagged. The player object just has a sprite on it, and is set to rigidbody. The script goes as follows:
using UnityEngine;
using System.Collections;
public class AIsciript : MonoBehaviour
{
private bool thisIsPlayer = true;
private GameObject objPlayer;
private GameObject objCamera;
//input variables (variables used to process and handle input)
private Vector3 inputRotation;
private Vector3 inputMovement;
//identity variables (variables specific to the game object)
public float moveSpeed = 100f;
// calculation variables (variables used for calculation)
private Vector3 tempVector;
private Vector3 tempVector2;
// Use this for initialization
void Start()
{
objPlayer = (GameObject)GameObject.FindWithTag("Player");
objCamera = (GameObject)GameObject.FindWithTag("MainCamera");
if (gameObject.tag == "Player")
{
thisIsPlayer = true;
}
}
// Update is called once per frame
void Update()
{
FindInput();
ProcessMovement();
if (thisIsPlayer == true)
{
HandleCamera();
}
}
void FindInput()
{
if (thisIsPlayer == true)
{
FindPlayerInput();
}
else
{
FindAIInput();
}
}
void FindPlayerInput()
{
//find vector to move
inputMovement = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
//find vector to the mouse
tempVector2 = new Vector3(Screen.width * 0.5f, 0, Screen.height * 0.5f);
// the position of the middle of the screen
tempVector = Input.mousePosition;
// find the position of the mouse on screen
tempVector.z = tempVector.y;
tempVector.y = 0;
Debug.Log(tempVector);
inputRotation = tempVector - tempVector2;
}
void FindAIInput()
{
}
void ProcessMovement()
{
rigidbody.AddForce(inputMovement.normalized * moveSpeed * Time.deltaTime);
objPlayer.transform.rotation = Quaternion.LookRotation(inputRotation);
objPlayer.transform.eulerAngles = new Vector3(0, transform.eulerAngles.y + 180, 0);
objPlayer.transform.position = new Vector3(transform.position.x, 0, transform.position.z);
}
void HandleCamera()
{
objCamera.transform.position = new Vector3(transform.position.x, 15, transform.position.z);
objCamera.transform.eulerAngles = new Vector3(90, 0, 0);
}
}
I just figured I would post the code just in case, but I figure it's probably not the issue, as I tried to force it to move in Start() and nothing happened.
You shouldn't be using all those checks for thisIsPlayer. You should have separate classes for the player entity and non-player entities.
Public variables are exposed in the editor and get serialized with the entity when the level is saved. This could mean that moveSpeed is not currently set to what it is initialized to in this class.
You shouldn't add force to a rigidbody in the Update method. There's a FixedUpdate method that's used for applying physics. This is because Update is called once per frame, no matter what the framerate, and FixedUpdate is only called at specific intervals, so physics forces aren't affected by framerate.
Also, you shouldn't try to apply a force and set the position of the transform of the same object. Strange things will happen.
If you go into the Unity Asset Store (available in the Window menu within Unity) there is a section called "Complete Projects" that contains some free tutorials. I can't remember which of them is written in C#, but even the JavaScript ones will give you some ideas on how to structure the project.
I don't know if I understood it right: your problem is that it is not moved by the AI?
if this is so, one problem could be that you initialize your
private bool thisIsPlayer = true;
with true but I can not see any condition setting it to false (enter ai mode)
just my 2 cents :)

Categories

Resources