I've got a problem with my script, I want the enemy of mine, follow and rotate towards the player. while he's moving around.
It seem to work nice, but when my player turning rotating 180 on y, my enemy seems to go back a lot(his position), and only when my player returning to his normal rotation , the enemy seem to come back.
What did I do wrong?
public class EnemyTesting : MonoBehaviour
{
public GameObject player;
public float speed = 1.5f;
public float turnRate;
private void Update()
{
Vector3 toTarget = player.transform.position - transform.position;
float angleToTarget = Vector3.Angle(transform.forward, toTarget);
Vector3 turnAxis = Vector3.Cross(transform.forward, toTarget);
transform.RotateAround(transform.position, turnAxis, Time.deltaTime * turnRate * angleToTarget);
transform.Translate(toTarget * speed * Time.deltaTime);
}
By "goes back" I understand rotation, not position.
I think that your problem is with Vector3.Angle. Check in the docs that the function returns the smaller of the two possible angles between the two vectors. In the case the angle is bigger than 180 you need to handle that in the code to make your enemy rotate accordingly.
Edit: I think that is produced by the rotation space of the translate function.
Set Space.World in the transform.Translate arguments
Try this:
private void Update() {
Vector3 toTarget = player.transform.position - transform.position;
transform.LookAt(player.transform.position);
transform.Translate(toTarget * speed * Time.deltaTime, Space.World);
}
You could use Quaternion.RotateTowards to slowly rotate the direction of the enemy towards the player.
This behavior also makes the enemy walk towards its forward vector, instead of directly at the player.
var towardsPlayer = player.transform.position - transform.position;
transform.rotation = Quaternion.RotateTowards(
transform.rotation,
Quaternion.LookRotation(towardsPlayer),
Time.deltaTime * turnRate
);
transform.position += transform.forward * speed * Time.deltaTime;
Related
how to make constant movement on z axis via character controller. I need my character to constantly move forward at the same speed
The forward axis of your character: transform.forward
Basic Solution with Transform:
public float speed = 2f;
public void Update()
{
transform.position += transform.forward * (speed * Time.deltaTime);
}
Relative movement with Transform.Translate;
transform.Translate(Vector3.forward * (speed * Time.deltaTime));
Basic Rigidbody velocity Setter:
private Rigidbody rigidbody;
public void Start()
{
rigidbody = GetComponent<Rigidbody>();
}
public void Update()
{
rigidbody.velocity = transform.forward * speed;
}
There are a couple ways of doing this. One is to simply move the object along the z axis via code with no care for physics. this will hold a constant velocity in that direction. You can hopefully see how this type of approach could e expanded for all directions by swapping out the zPosChange float for a vector representing the direction you want to move in. This is a kinematic position update.
public float speed = 10;
void Update()
{
float zPosUpdate = gameObject.transform.position.z
zPosUpdate += speed * Time.deltaTime;
gameObject.transform.position = new Vector3(gameObject.transform.position.x, gameObject.transform.position.y, zPosUpdate );
}
The other way is to use the unity physics system to add force to a rigidbody component. To do this you must first have added a rigidbody and a collider to the object you are controlling. Since we want constant velocity and not acceleration and deceleration I wouldn't recommend that unless you really need the object to be able to be affected physically by collisions. You would do similar to the example I've given here but instead of the transform position you would set the velocity on the rigidbody component.
You can use Add Force to you character.
character_Rigidbody.AddForce(transform.forward * speed* Time.deltaTime);
I have a virtual movement joystick that I'm using to control the movement of a player object which works fine, the code for this is below.
The problem I have is when I rotate the camera within game mode (or device) the direction is not adjusted according to the cameras rotation, exactly like is shown in this post here that I looked through to try and understand the problem.
I realise I need to rotate my movement around the forward direction the camera is facing which I tried to do with the bottom snippet of code however this yields really strange behavior when the player object moves incredibly fast and eventually unity becomes unresponsive, so something is being incorrectly multiplied I guess.
Could anybody point out where I'm going wrong please? ta !
Edit - Modified to potential answer
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using EasyJoystick;
public class NewJoystick : MonoBehaviour
{
[SerializeField] private float speed;
[SerializeField] private Joystick1 joystick;
[SerializeField] Camera MainCam;
private Rigidbody RB;
private Transform cameraTransform;
// Start is called before the first frame update
void Start()
{
cameraTransform = MainCam.transform;
}
void Awake()
{
RB = gameObject.GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
float xMovement = joystick.Horizontal();
float zMovement = joystick.Vertical();
Vector3 inputDirection = new Vector3(xMovement, 0, zMovement);
//Get the camera horizontal rotation
Vector3 faceDirection = new Vector3(cameraTransform.forward.x, 0, cameraTransform.forward.z);
//Get the angle between world forward and camera
float cameraAngle = Vector3.SignedAngle(Vector3.forward, faceDirection, Vector3.up);
//Finally rotate the input direction horizontally by the cameraAngle
Vector3 moveDirection = Quaternion.Euler(0, cameraAngle, 0) * inputDirection;
RB.velocity = moveDirection * speed;
}
}
I tried this in the update loop -
var Direction = transform.position += new Vector3(xMovement, 0f,zMovement); //* speed * Time.deltaTime;
Vector3 newDir = MainCam.transform.TransformDirection(Direction);
transform.position += new Vector3(newDir.x, 0f,newDir.z) * speed * Time.deltaTime;
Well, here is a simple idea for how to solve it. At least this is how I did it, and it seems to work ever since.
First, you need to get the joystick input, like you did. Both axis input value should be between -1 and 1. This actually determines the direction itself, since the horizontal axis gives you the X coordinate of a vector and the vertical gives you the Y coordinate of that vector. You can visualize it easily:
Mind, that I just put up some random values there, but you get the idea.
Now, your problem is, that this angle you get from your raw input is
static in direction, meaning that it doesn't rely on the camera's face
direction. You can solve this problem by "locking it to the camera",
or in other words, rotate the input direction based on the camera
rotation. Here's a quick example:
//Get the input direction
float inputX = joystick.Horizontal();
float inputY = joystick.Vertical();
Vector3 inputDirection = new Vector3(inputX, 0, inputY);
//Get the camera horizontal rotation
Vector3 faceDirection = new Vector3(cameraTransform.forward.x, 0, cameraTransform.forward.z);
//Get the angle between world forward and camera
float cameraAngle = Vector3.SignedAngle(Vector3.forward, faceDirection, Vector3.up);
//Finally rotate the input direction horizontally by the cameraAngle
Vector3 moveDirection = Quaternion.Euler(0, cameraAngle, 0) * inputDirection;
IMPORTANT: The code above should be called in the Update cycle, since that is where you get the input information.
After this, you can work with moveDirection to move your player. (I suggest using physics for moving, instead of modifying its position)
Simple moving example:
public RigidBody rigidbody;
public Vector3 moveDirection;
public float moveSpeed = 5f;
void FixedUpdate()
{
rigidbody.velocity = moveDirection * moveSpeed;
}
I have been trying this for two days with no success. I cant figure out where I'm missing the point. All the missiles are moving towards the position of the target but not following it. The position remains fixed and all the newly created missiles come to this point instead of following the target.
Here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HomingMissile : MonoBehaviour
{
private GameObject target; //changed to private
private Rigidbody rb;
public float rotationSpeed;
public float speed;
Quaternion rotateToTarget;
Vector3 direction;
private void Start()
{
target = GameObject.FindGameObjectWithTag("Player"); //uncommented this
rb = GetComponent<Rigidbody>();
}
private void FixedUpdate()
{
//made some modifications
Vector3 direction = (target.transform.position - transform.position).normalized;
float angle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg;//interchanged x and z
Quaternion rotateToTarget = Quaternion.Euler(0, angle, 0);
transform.rotation = Quaternion.Slerp(transform.rotation, rotateToTarget, Time.deltaTime * rotationSpeed);
Vector3 deltaPosition = speed * direction * Time.deltaTime;
rb.MovePosition(transform.position + deltaPosition);
}
}
I selected the target(transform) using the inspector.
I'm using Unity and C# obviously you know that.
What Im trying to achieve is that the missile should follow the position of the target in real time. And i can add the destroy code for the missile myself.
Note :
Please don't tag this as a duplicate. It is not.
The game is 2D where Y is always constant. Vertical axis is X and Horizontal axis is X. The objects are 3D. That's why I can't use rigidbody2D.
EDIT:
Code edited. The missile follows the target and also points to the direction of motion. How to make the missile make a circular rotation when it needs to rotate?
Firstly, consider:
Not modifying a rigidbody.velocity directly, as it will result in unrealistic behaviour
Using FixedUpdate() instead of Update() when controlling rigidbodies
Use rigidbody.movePosition() and rigidbody.moveRotation() instead. Here's an example:
Vector3 dir = (target.transform.position - transform.position).normalized;
Vector3 deltaPosition = speed * dir * Time.deltaTime;
rb.MovePosition(transform.position + deltaPosition);
Try out rigidbody.MoveRotation() yourself for practice.
Finally, understand that there are many ways to implement homing for missiles. Here's one that is commonly used in real life.
Edit: I will not recommend using rb.addForce() because if u try it out u will realise it is too indeterministic.
I'm building a top down shooter and so I have my camera above my player and the map. Here's the code I've written in the player controller script for movement:
public class playerMovement : MonoBehaviour {
public float speed;
private Camera mainCamera;
void Start () {
mainCamera = FindObjectOfType<Camera>();
}
// Update is called once per frame
void Update () {
// player movement
transform.Translate(speed * Input.GetAxis("Horizontal") * Time.deltaTime, 0f, speed * Input.GetAxis("Vertical") * Time.deltaTime);
// Camera Ray casting
Ray cameraRay = mainCamera.ScreenPointToRay(Input.mousePosition);
Plane groundPlane = new Plane(Vector3.up, Vector3.zero);
float rayLength;
if (groundPlane.Raycast(cameraRay, out rayLength)) {
Vector3 look = cameraRay.GetPoint(rayLength);
Debug.DrawLine(cameraRay.origin, look, Color.red);
transform.LookAt(new Vector3(look.x, transform.position.y, look.z));
}
}
}
I want to be able to move the player using the WASD keys and also rotate following the direction on where the mouse is, however I don't want the rotation of the player to change the direction of the keys, I need the player to move forwards if the W key is pressed no matter which way the player is facing.
However for some reason my code makes the player move forwards depending on which way it is facing which I don't want.
How can I fix this?
The problem is that your transform.Translate call is in "self" space. Forward, backward, left, right are all relative to the direction the transform is facing. That is why your player is moving relative to the facing direction.
If you want to translate relative to "global" or "world" space, you have to add an additional parameter.
// player movement
transform.Translate(speed * Input.GetAxis("Horizontal") * Time.deltaTime,
0f,
speed * Input.GetAxis("Vertical") * Time.deltaTime,
Space.World);
Note the Space.World parameter at the end, to set the world coordinate system.
You can find more in the Unity docs here: https://docs.unity3d.com/ScriptReference/Transform.Translate.html
You need to look at the difference between local and global coordinate systems.
Right now your WASD keys are moving the player character according to global coordinates, and you want the WASD movement to be dependant on the player's orientation so you need to use a local coordinate system.
http://wiki.unity3d.com/index.php?title=Converting_Between_Coordinate_Systems
I am currently making a flight simulator. Right now, I am trying to get the plane to fly on its own, but I am having some problems with trying to rotate the plane such that it is parallel to the ground.
This is my code:
heightDetect = new Ray (transform.position, Vector3.down);
if (Physics.Raycast (heightDetect, out hit, Mathf.Infinity)) {
Debug.Log (hit.distance);
transform.rotation = Quaternion.FromToRotation(transform.up, hit.normal) * transform.rotation;
Debug.DrawRay (heightDetect.origin, heightDetect.direction*1000);
}
The code works and all, but the problem is it is way too bumpy. The camera on the plane keeps jerking about on my screen, and is completely unplayable. Is there a way to smoothen this process? Thank you!
Presumably you are doing this in your Update function, and therefore changing the rotation of your plane many times per second. Instead of directly setting the rotation, you could use spherical linear interpolation:
public float speed = 0.1f;
void Update() {
...
var targetRotation = Quaternion.FromToRotation(transform.up, hit.normal) * transform.rotation;
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * speed);
}
This effectively smoothes the rotation over time. It works by taking the current rotation and the eventual desired rotation, but only returning a rotation somewhere in between (controlled by speed).
If I understand correctly, you're looking for the Quaternion.Lerp to smooth your rotation for Quaternions, or Mathf.LerpAngle for Vector3 rotation.
Usage example:
Vector3 currentRotation = transform.rotation;
Vector3 newRotation = Quaternion.FromToRotation(transform.up, hit.normal) * transform.rotation;
newRotation = new Vector3(
Mathf.LerpAngle(currentRotation.x, newRotation.x, Time.deltaTime),
Mathf.LerpAngle(currentRotation.y, newRotation.y, Time.deltaTime),
Mathf.LerpAngle(currentRotation.z, newRotation.z, Time.deltaTime));
transform.rotation = newRotation;
Multiply Time.deltaTime by any value to change lerp's "speed".