Im making a game in Unity. My task is to when player presses the "1' key, it shoots out a sphere to the player.transform.forward position, until it collides with an enemy.
The problem is, when the sphere has been shot, while its flying, I can controll its moving X value by turning the player right or left. So the sphere moves with me, but it should not. This is of course because in Update(), I move it in the player's facing direction. How can I make the sphere start facing at the players direction, but after move independently?
This is the code that moves the sphere
private float speed = 4.0f;
void Update()
{
transform.Translate(player.transform.forward * Time.deltaTime * speed);
}
You could save it's inital "forward" direction and reference it afterwards
public GameObject player;
private float speed = 4.0f;
private Vector3 direction;
private void Awake() //I used Awake() as example asuming you are instantiating the sphere,
{ //but you could set the value of the direction when you press "1" too
direction = player.transform.forward;
}
void Update()
{
transform.Translate(direction * Time.deltaTime * speed);
}
Instantiate it with the correct orientation
Instantiate(rangedAttack, spawnPosition, player.transform.rotation);
Now its own forward vector points the same direction as the one of the player.
And then simply do
private float speed = 4.0f;
void Update()
{
transform.Translate(Vector3.forward * Time.deltaTime * speed);
}
Note Translate by default works in the Space.Self so the local space of this transform. You do not want to pass in a worldspace Vector here but rather move only in the local Z axis!
If you pass in a worldspace vector you will nee to pass Space.World
transform.Translate(vector, Space.World);
Related
I have the following script which should make the main camera follow and rotate with the player's movements.
public class FollowPlayer : MonoBehaviour
{
[SerializeField]
float mouseSensitivity;
public Vector3 cameraOffset;
public Transform Player;
public Transform mainCamera;
void Start()
{
Cursor.lockState = CursorLockMode.Locked;
cameraOffset = transform.position - Player.transform.position;
}
void Update()
{
Rotate();
}
private void Rotate()
{
float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * Time.deltaTime;
Player.Rotate(Vector3.up, mouseX);
mainCamera.Rotate(Vector3.up, mouseX); //shows abnormal rotation (hides the player as well)
}
private void LateUpdate()
{
Vector3 newPosition = Player.position + cameraOffset;
transform.position = newPosition;
}
}
The camera follows the player, however, but it does not rotate with the player's rotations. Please note that making the main camera the child of the player is not an option here, since I have to use this script on multiplayer. I want the mouse to be able to rotate both the main camera and the player at the same time.
The reason the camera is not rotating, is that you capture the initial offset on start, which is expressed in absolute (world space) position. This can be easily fixed using transform.TransformPoint method. What you then need to do is address camera rotation. In the simplest case you can just use 'LookAt' method
private void LateUpdate()
{
Vector3 newPosition = Player.position + Player.TransformPoint(cameraOffset);
mainCamera.position = newPosition;
mainCamera.LookAt(Player.position, Vector3.up);
}
I also noticed that you use transform.position (a transform from the object your script is attached to) but then you also use mainCamera transform as a seperate transform, mixing it like that might lead to confusion later. You should either always access the camera via mainCamera reference, or you could always keep the script attached to the camera and use transform reference.
I also noticed that you use one script to do two seperate things, it controls both player rotation and camera position/rotation while following the player. While there is nothing stoping you from doing that, its often a good idea to split it into doing two things each doing one logical thing
I have a character/rigidbody and 'she' can turn around. When I press Play in Unity, if I move forward/backward, that's fine, she moves forward/backward. It's a good start.
But then if I turn her left or right, then go forward/backward, she now moves sideways.
She is a rigidbody component set as a parent in the scene.
Surely it's not difficult to do, but I can't figure out how to set her rotation so that when she turns, she will move 'forward' when I press the button to move her forward! There are plenty of first-person-shooter games where you can turn and move 'forward' and the player goes in the correct direction.
My rotation script at the moment is this:
Vector3 EulerAngleVelocity;
public float rotateSpeed = 250.0f;
void Update() {
if (Input.GetKey(KeyCode.UpArrow) || Input.GetKey(KeyCode.DownArrow))
{
MoveVector = PoolInput();
Move();
}
if (Input.GetKey(KeyCode.RightArrow))
{
EulerAngleVelocity = new Vector3(0, rotateSpeed, 0);
Quaternion deltaRotation = Quaternion.Euler(EulerAngleVelocity * Time.deltaTime);
rigidbody.MoveRotation(rigidbody.rotation * deltaRotation);
}
}
private void Move()
{
rigidbody.AddForce((MoveVector * moveSpeed));
}
private Vector3 PoolInput()
{
Vector3 dir = Vector3.zero;
dir.x = joystick.Horizontal();
dir.z = joystick.Vertical();
if (dir.magnitude > 1)
dir.Normalize();
return dir;
}
You're moving your joystick and adding that direction in relation to the WORLD instead of in relation to your player. If you want to add force relative to the orientation of the RigidBody probably what you want to use is rigidBody.AddRelativeForce (documentation) instead of simply rigidBody.AddForce.
Your problem isn't your rotation code, it's your movement code. You're applying a motion in world-space, not local-space ('object'-space).
For example, if you're using Vector3.Forward, you will want to use transform.Forward instead.
I am trying to instantiate a prefab, a fireball, from a baddie, and at the time of instantiation pass the current player position to the fireball and use this to target the fireball at the player. The fireball translates/moves forward on its transform.forward vector. Thus the fireball should head from the baddie towards the player's position at the time the fireball was created.
What I am finding is that the direction is being set (via the transform.lookat() function on the fireball), but it is almost always the wrong direction. It is not 90 or 180 off. How much it is off by depends on where the player is in respect to the baddie. The pattern is symmetrical around the z axis.
Assuming the baddie is at (0,0,0):
when the player is at (0,0,10) the fireballs head directly towards the player
when the player is at (0,0,-10) the fireballs head away from the player (180 degrees. The exact opposite direction. The same direction as when the player was at (0,0,10))
when the player is at (10,0,0) the fireballs head 90 degrees away from the player (to the players right if facing the baddie)
when the player is at (-10,0,0) the fireballs head 90 degrees away from the player (to the players left if facing the baddie)
These values move smoothly as the player moves through these angles. It only ever hits the player in one direction.
I have tried the following (some of these were probably not required):
re-import all assets
create new project on a new machine to reproduce the issue.
I've tried setting the lookat variable to be:
player transform
the vector 3 world coordinate of the player (this is what is in the code below)
player.transform.position - baddie.transform.position
baddie.transform.position - player.transform.position
These all yield the same results.
Here is my code.
Code to Instantiate the fireball from the baddie.
public class Baddie : MonoBehaviour {
public GameObject fireballPrefab;
public GameObject playerGameObject;
public float countDownForFireball;
private float currentCountDownForFireball;
void Start () {
playerGameObject = GameObject.FindGameObjectWithTag("Player");
currentCountDownForFireball = 0;
}
void Update () {
if(currentCountDownForFireball <= 0)
{
GameObject newFireball = GameObject.Instantiate(fireballPrefab, transform.position, Quaternion.identity);
newFireball.GetComponent<Fireball>().SetTarget(playerGameObject.transform.position);
currentCountDownForFireball = countDownForFireball;
}
else
{
currentCountDownForFireball -= Time.deltaTime;
}
}
}
Code on the fireball
public class Fireball : MonoBehaviour {
private float moveSpeed;
private Vector3 target;
// Use this for initialization
void Start () {
moveSpeed = 15f;
}
// Update is called once per frame
void Update (){
transform.Translate(transform.forward * Time.deltaTime * moveSpeed);
}
public void SetTarget(Vector3 newTarget){
target = newTarget;
transform.LookAt(target);
}
}
The error is in the usage of Transform.Translate. Its secondary parameter is a Space argument that defaults to Space.Self. You want the space of your direction to match the space you're translating in so you want to pass in Space.World:
// transform.forward is the transform's forward vector in "world space"
transform.Translate(transform.forward * Time.deltaTime * moveSpeed, Space.World);
Alternatively, you can keep using the default Space.Self with Vector3.forward instead of transform.forward:
// Vector3.forward is (0,0,1). In "self space" this is "forward"
transform.Translate(Vector3.forward * Time.deltaTime * moveSpeed); // Space.Self
Needed help here, I've been following this tutorial about Enemy Patrolling, https://www.youtube.com/watch?v=KKU3ejp0Alg
The tutorial tell us to set 2 Empty Game Objects and the coordinates so the sprite will walk from one direction to another, the walking does working, however the rotation of the sprite became really weird, the 'Worm' sprite is suppose to move left and right now it change into facing upward
Please look at this image,
When moving from left to right
When moving from right to left
public Transform[] patrolPoints;
public float speed;
Transform currentPatrolPoint;
int currentPatrolIndex;
// Use this for initialization
void Start()
{
currentPatrolIndex = 0;
currentPatrolPoint = patrolPoints[currentPatrolIndex];
}
// Update is called once per frame
void Update()
{
transform.Translate(Vector3.up * Time.deltaTime * speed);
if (Vector3.Distance(transform.position, currentPatrolPoint.position) < .1f) {
if (currentPatrolIndex + 1 < patrolPoints.Length)
currentPatrolIndex++;
else
currentPatrolIndex = 0;
currentPatrolPoint = patrolPoints[currentPatrolIndex];
}
Vector3 patrolPointDir = currentPatrolPoint.position - transform.position;
float angle = Mathf.Atan2(patrolPointDir.y, patrolPointDir.x) * Mathf.Rad2Deg - 90f;
Quaternion q = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = Quaternion.RotateTowards(transform.rotation, q, 180f);
}
This is the code
Thank you
You can pass the optional parameter Space.World to your translation to move your object relative to world space instead of object space. That should prevent your object from rotating.
transform.Translate(Vector3.up * Time.deltaTime * speed, Space.World);
You can read more about it in the documentation.
You probably rotated the enemy sprite by 90 degrees. Try placing all your scripts into empty game object with no rotation, than place the enemy sprite as child of the empty game object and rotate as you need. This way your logic won't collide with your graphics.
I am having a problem with the camera following the player. When the player moves, the camera shakes and this effect is more noticeable when the player is in the crouched position. I am using root motion for the player with animations by mixamo.
Player Script:
Transform cameraT;
void Start () {
cameraT = Camera.main.transform;
}
void FixedUpdate ()
{
float sideMotion = Input.GetAxis("SideMotion");
float straightMotion= Input.GetAxis("StraightMotion");
if (Mathf.Abs(sideMotion) > 0 || Mathf.Abs(straightMotion) > 0)
{
transform.eulerAngles = new Vector3(transform.eulerAngles.x,
cameraT.eulerAngles.y);
}
}
Camera Script:
public float distanceFromPlayer=2f;
public float mouseSensitivity=6;
public Transform player;
public Vector2 pitchConstraint= new Vector2(-30,80);
Vector3 rotationSmoothVelocity;
Vector3 currentRotation;
public float rotationSmoothTime = 0.2f;
float yaw; //Rotation around the vertical axis is called yaw
float pitch; //Rotation around the side-to-side axis is called pitch
private void LateUpdate()
{
yaw += Input.GetAxis("Mouse X") * mouseSensitivity;
pitch -= Input.GetAxis("Mouse Y") * mouseSensitivity;
pitch = Mathf.Clamp(pitch, pitchConstraint.x, pitchConstraint.y);
currentRotation = Vector3.SmoothDamp
(currentRotation, new Vector3(pitch, yaw), ref rotationSmoothVelocity, rotationSmoothTime);
transform.eulerAngles = currentRotation;
transform.position = player.position - transform.forward * distanceFromPlayer;
}
For public transform I just added an empty game object to player chest level and parented it to the player. I got the rotating camera smoothly trick from an online tutorial but that exact thing won't work on player rotation though.
A character controller is attached to player without any rigidbody or collider.
You are going to want to use Lerp on the camera in order to smooth its motion from one position to another. The Scripting API has a good example of Vector3.Lerp.
So in your case, you could add a public variable for smoothing position as well. Something like positionSmoothTime. Then make a "Desired Position" variable, we'll call it destPosition.
Vector3 destPosition = player.position - transform.forward * distanceFromPlayer;
transform.position = Vector3.Lerp(transform.position, destPosition, positionSmoothTime);
This should effectively smooth it to where the stuttering should go away. Another thing that will help that someone else mentioned is using a part of the body that moves less (Like the head) as the target. This combined with the Lerp function will give you a smooth camera movement.
Another large help would be to move things into the Update() function. The reason being is FixedUpdate() doesn't get called every frame. So you could potentially get stutter as a result. If you move everything into Update() it will update every frame and help smooth things out. If you do this though you will need to multiply all movement by Time.deltaTime as shown in the example below.
Vector3 destPosition = (player.position - transform.forward * distanceFromPlayer) * Time.deltaTime;
For more examples, check the links to each function to see Unity's documentation on it. It has examples of everything I've shown here.