I made an 2D endless runner game using Unity, where the Player Object moves upwards, but for the Viewer he remains on the same spot because the Camera is following him. The Following works pretty well, but the problem is that it is making small jumps every few seconds. The jumps are small and thus are not affecting the gameplay in general but they are big enough to make it seem like the game is not running smoothly.
I can't even tell whether it is the Camera that is making the jumps or the Player Object. But I think it is the Camera, because the spawning obstacles are also making jumps. What may be the issue? Am I using the right method for the Camera?
public class Player
{
float speed = 5f;
void Update()
{
transform.Translate(0, speed*Time.deltaTime, 0);
}
}
And this is the Script which is attached to the Camera:
public class CameraFollow
{
private Vector3 FollowVector;
public Transform Player;
void LadeUpdate()
{
FollowVector = Player.position - new Vector3(0, -4f, 10);
transform.position = Vector3.Lerp(transform.position, FollowVector, Time.deltaTime * 4f);
}
}
Does the jump happen every 4 seconds? I think the problem might be in your Vector3.Lerp function. It's basically a loose camera-follow, that takes 4 seconds (Time.deltaTime * 4f) to smoothly go from Point A to point B. Every 4 seconds it resets its path, hence the hop. At least that's my theory.
If you don't mind the camera rigidly following the player, I would just remove the Lerp and just set the transform.position to be the FollowVector value like so:
void LadeUpdate()
{
transform.position = Player.position - new Vector3(0, -4f, 10);
}
Try to use Vector3.MoveTowards
float step = speed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, Player.position - new Vector3(0, -4f, 10f), step);
Related
hi everyone so basically I was wondering how I could change this movement script to be with rigidbody. It works the way I want it to with wasd to change look direction and then space to move forward from that direction kinda but I want to convert it all to be done with rigidbody so I can do collisions. Thanks!!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Fly : MonoBehaviour
{
public float moveSpeed;
void Start()
{
}
void Update()
{
if (Input.GetKey(KeyCode.Space))
{
transform.Translate(new Vector3(0,0,moveSpeed) * Time.deltaTime, Space.Self);
}
float rotatex = Input.GetAxis("Vertical");
float rotatey = Input.GetAxis("Horizontal");
transform.Rotate(0, rotatey, 0, Space.World);
transform.Rotate(-rotatex * 0.5f, 0, 0);
}
}
There are quite a few errors with your code as written. No problem, but you'll probably need to fix all of these before your code starts working as intended. This answer is meant to give you a springboard to google up on some of these errors and wrap your head around the Update() method and how it works in Unity.
First, you'll need to ensure the RigidBody2d component is on your Game Object. That's easy enough to do, right click in the inspector and add the component. Google: "How do I add components to game objects in Unity"
Next, you're going to want to understand how often Update() is called and how it works. Spoiler alert - it's called as fast as your computer can. What that means is that changing the rotation with transform.Rotate every call is likely going to lead to an object that's spinning extremely rapidly. Perhaps rapidly enough that it's spinning more than 360 degrees each frame and just appears to be "twitching" randomly. You'll need to scale your rotation, so Google up "delta time in Unity Update".
Lastly, you're going to want to collect your inputs, which you're doing correctly with Input.GetKey(), although there are lots of ways to skin this cat. Perhaps the most straightforward would be to collect your inputs in one method called GetAllInputs(), set some booleans in that method to things like IsMovingRight or IsJumping and then operate on them in your Update method. This is only one approach, there are literally dozens, and many ways that they can be improved. Google up "Unity Input System", "Unity 2D Physics", and "Finite State Machines" (since you're eventually going to want to have "states" like crouching, jumping, running, hanging on to a wall, etc). It seems like you're writing a platformer, so I'd also watch some of the youtube tutorials on that, and google phrases like "Creating a Unity Platformer Tutorial".
Assuming it works the way you want here is the code using rigidbody (Make Sure Rigid Body is attached to object) This code must be written in Fixed Update as RigidBody based calculation must be done in Fixed Update:
public class Fly : MonoBehaviour
{
public float moveSpeed;
[SerializeField] private Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
if (Input.GetKey(KeyCode.Space))
{
//transform.Translate(new Vector3(0,0,moveSpeed) *
//Time.deltaTime, Space.Self);
if (rb)
{
rb.MovePosition(new Vector3(0,0,moveSpeed) *
Time.deltaTime);
}
}
float rotatex = Input.GetAxis("Vertical");
float rotatey = Input.GetAxis("Horizontal");
// transform.Rotate(0, rotatey, 0, Space.World);
// transform.Rotate(-rotatex * 0.5f, 0, 0);
if (rb)
{
rb.MoveRotation(Quaternion.Euler(rotatex , rotatey , 0));
}
}
}
I'm pretty new to Unity. I tried to create a script that the camera would follow the actor (with a little difference). Is there a way to improve the code? It works just fine. But I wonder if I did it the best way. I want to do it about as I wrote, so if you have any tips. Thank you
Maybe change Update to FixedUpdate ?
public GameObject player;
// Start is called before the first frame update
void Start()
{
player = GameObject.Find("Cube"); // The player
}
// Update is called once per frame
void Update()
{
transform.position = new Vector3(player.transform.position.x, player.transform.position.y + 5, player.transform.position.z - 10);
}
Making the camera following the player is quite straight forward.
Add this script to your main camera.
Drag the reference of the player object to the script and then you are done.
You can change the values in the Vector 3 depending on how far you want the camera to be from the player.
using UnityEngine;
public class Follow_player : MonoBehaviour {
public Transform player;
// Update is called once per frame
void Update () {
transform.position = player.transform.position + new Vector3(0, 1, -5);
}
}
Follows player in the back constantly when the player rotates, no parenting needed, with smoothing.
Piece of Knowledges:
Apparently, Quaternion * Vector3 is going to rotate the point of the Vector3 around the origin of the Vector3 by the angle of the Quaternion
The Lerp method in Vector3 and Quaternion stand for linear interpolation, where the first parameter gets closer to the second parameter by the amount of third parameter each frame.
using UnityEngine;
public class CameraFollow : MonoBehaviour
{
public Transform target;
public float smoothSpeed = 0.125f;
public Vector3 locationOffset;
public Vector3 rotationOffset;
void FixedUpdate()
{
Vector3 desiredPosition = target.position + target.rotation * locationOffset;
Vector3 smoothedPosition = Vector3.Lerp(transform.position, desiredPosition, smoothSpeed);
transform.position = smoothedPosition;
Quaternion desiredrotation = target.rotation * Quaternion.Euler(rotationOffset);
Quaternion smoothedrotation = Quaternion.Lerp(transform.rotation, desiredrotation, smoothSpeed);
transform.rotation = smoothedrotation;
}
}
This will always follow the player from the same direction, and if the player rotates it will still stay the same. This may be good for top-down or side-scrolling view, but the camera setup seems to be more fitting for 3rd person, in which case you'd want to rotate the camera when the player turns.
The easiest way to do this is actually not with code alone, simply make the camera a child of the player object, that way its position relative to the player will always stay the same!
If you do want to do it through code, you can change the code to be like this:
void Update()
{
Vector3 back = -player.transform.forward;
back.y = 0.5f; // this determines how high. Increase for higher view angle.
transform.position = player.transform.position - back * distance;
transform.forward = player.transform.position - transform.position;
}
You get the direction of the back of the player (opposite of transform's forward). Then you increase the height a little so the angle will be a bit from above like in your example. Last you set the camera's position to be the player's position and add the back direction multiplied by the distance. That will place the camera behind the player.
You also need to rotate the camera so it points at the player, and that's the last line - setting the camera's forward direction to point at the player.
Here is just another option. I always find it easier to have the variables which are populated in the inspector so you can adjust it and fine tune it as needed.
public GameObject player;
[SerializeField]
private float xAxis, yAxis, zAxis;
private void Update()
{
transform.position = new Vector3(player.transform.position.x + xAxis, player.transform.position.y + yAxis, player.transform.position.z + zAxis);
}
I recently posted a problem with a jittering Camera Follow in my 2D Game made in Unity, which was solved here.
However after some time I noticed, that I am still getting jumps. I now know, that the problem lies in the lerp method of my camera follow. Time.deltaTime varies as described in my prior question and thus makes the player move different distances each frame. But because the camera reacts with a delay, you can see the jump on screen (on device even more than in Unity Editor).
A solution would be to detect those Time.DeltaTime jumps and in these cases make the camera imitate that jump somehow, am I correct? What would be a Workaround here?
These are my scripts:
public class Player: MonoBehaviour
{
float speed = 5f;
void Update()
{
transform.Translate(0,speed*Time.deltaTime,0);
}
}
public class CamFollow : MonoBehaviour
{
public Transform Player;
private Vector3 FollowVector;
float transition = 0.05f;
void LateUpdate()
{
FollowVector = Player.position - new Vector3(0, -4.0f, 10);
transform.position = Vector3.Lerp(transform.position, FollowVector, transition);
}
}
Try using Time.fixedDeltaTime. This is like deltatime but it's fixed and so it doesn't very as you said. It does reduce the jittering, but I would recommend using Cinemachine, as it's very performant and you would have a lot of control over it.
This the strangest thing i ever saw, i swear! So i have a script to the player that when you click on screen the cube jumps in the direction of the arrow(the arrow rotates 360 degres).I changed some settings to the rigidbody2d to make the jump better.Now here comes the strange part,when i run the game and the player is selected in the scene or hierrachy the jump works fine,if i select something else for exemple the camera something chenges the jump,from a very good one to a very bad one,i tryed to build the project and test and is the same,the cube dosen't have the same "Jump".I think it's becouse i changed something in the rigidbody,idk.PLS HELP!!!center
P.S if u ask for the script here it is :
public void Update()
{
Lava.transform.position = new Vector2(transform.position.x, Lava.transform.position.y);//other,not important
cam.transform.position = transform.position + offset;//camera follow player
Arrow.transform.RotateAround(gameObject.transform.position, new Vector3(0, 0, 180), ArrowSpeed * Time.deltaTime); //to make the arrow rotate 360
if (Input.GetMouseButtonDown(0))
{
rb.AddForce(Arrow.transform.right * -ImpulseForce * Time.deltaTime, ForceMode2D.Impulse); //this makes the cube jump
}
//other
score = (int) transform.position.y;
ScoreUI.text = score.ToString();
}
Firstly, RotateAround method takes a normalized vector as its second parameter, such as Vector3.forward in your case.
Secondly, applying any force to a rigidbody should be done in FixedUpdate, not Update (see Rigidbody.AddForce and ForceMode)
In your case it's an impulse, and it's only called when you click, so no need to multiply by delta time.
rb.AddForce(Arrow.transform.right * -ImpulseForce, ForceMode2D.Impulse);
It may not solve all of your issues, but without further information it's tough to know. At least you wont have weird physics behaviors anymore.
First of all: Sorry for my bad English, I'm Dutch.
I'm trying to create a player object that can walk forward and backwards (with the up and down keys), and rotate the player with the right and left keys. But when I press the left or right key, the position of the player changes, it looks like it rotates around a certain point. But it should rotate and stay on the same place, like I do when I turn around.
I have some other small programs, with the same 'move script' and the same inputmanager settings. There it works fine, so I have no idea why it doesn't work this time.
This is my move script, but this script works fine with other programs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveScript : MonoBehaviour
{
public float speed = 3f;
public float rotate = 50f;
private Rigidbody rb;
// Update is called once per frame
private void Start()
{
rb = GetComponent<Rigidbody>();
}
void Update()
{
if (Input.GetButton("Up"))
transform.Translate(Vector3.forward * speed * Time.deltaTime);
if (Input.GetButton("Down"))
transform.Translate(-Vector3.forward * speed * Time.deltaTime);
if (Input.GetButton("Right"))
transform.Rotate(Vector3.up, rotate * Time.deltaTime);
if (Input.GetButton("Left"))
transform.Rotate(-Vector3.up, rotate * Time.deltaTime);
if (gameObject.GetComponent<Rigidbody>().velocity.y < 0.01)
{
if (Input.GetButtonDown("Jump"))
rb.AddForce(0, 225, 0);
}
}
}
The InputManager settings (also the same as other programs where it works fine):
If someone wants a screenshot of something else of my program, you can always ask it of course. I have no idea what the problem could be, if it isn't in the script or the inputmanager.
Following the comments in the OP, the solution should be to use:
if (Input.GetButton("Right"))
transform.localEulerAngles = transform.localEulerAngles + new Vector3(xRotation, 0, 0) * Time.deltaTime;
if (Input.GetButton("Left"))
transform.localEulerAngles = transform.localEulerAngles - new Vector3(xRotation, 0, 0) * Time.deltaTime;
Where xRotation is a float with the amount you want to rotate per second when and while one of the rotation keys is down.
(PS: Don't have unity open right now, so + and - might be inverted, but should be something like that.)