Smooth Camera Follow in Unity for 2D Platformer - unity3d

I've been scouring the internet for the past couple of hours trying to find a working solution to this. I've tried everything I could possibly think of: different types of functions, different types of updates, different smoothing times. Below is a video of how my game currently plays. I'm making a small platformer just for practice, and I want to get this camera problem out of the way! Click here for video
Here is my current code, but again, I've tried numerous other combinations, too. Thanks for all the help.
using UnityEngine;
public class CameraFollow : MonoBehaviour {
public Transform target;
public Vector3 offset;
public float smoothTime = 0.3f;
private Vector3 velocity;
private void LateUpdate()
{
transform.position = Vector3.SmoothDamp(transform.position, target.position + offset, ref velocity, smoothTime);
}
}
EDIT:
I've tried a bunch of other suggestions, but nothing is still working. If this helps, I'm running Unity 2018.2.5f1 Personal 64 bit. I'm using a Razer Blade 15 2018.

You can try the code below. This piece of code works for me in my 3D game.
public float translationFactor = 20;
void LateUpdate(){
if(transform.position != target.position) {
transform.position += (target.position - transform.position) / translationFactor;
}
}
This is a direct quote about why you should use LateUpdate() when you are working with cameras, from Unity3D's LateUpdate() documentation.
LateUpdate is called after all Update functions have been called. This
is useful to order script execution. For example a follow camera
should always be implemented in LateUpdate because it tracks objects
that might have moved inside Update.
Also I've noticed that you use Vector3 instead of Vector2 in a 2D game. I'm not experienced in 2D as much as I'm in 3D so I don't know if it will make any difference to replace Vector3s with Vector2s.

I haven't tested this, but it should work if you simply change the function name from LateUpdate to Update, if I understand your problem correctly.

I am thinking your problem on your skeleton script. Your camera follows skeleton and you are thinking problem on camera
Try to move skeleton with AddForce instead of transform.position
Example
void Update () {
if (Input.GetMouseButtonDown (0)) {
GetComponent<AudioSource> ().PlayOneShot (voices[2]);
birdSpeed.velocity = Vector2.zero;
birdSpeed.AddForce (new Vector2 (0, birdUp));
}
public void Buttons(int i){
if (i == 0) {
birds = 0.2f;
GetComponent<Rigidbody2D> ().gravityScale = 4;
birdUp = 400;
StartPanel.SetActive (false);
GamePanel.SetActive (true);
GameOverPanel.SetActive (false);
}
In this code when i click to mouse bird up and you can adapt your code to this

i know im late but for all of you asking this question i looked in to your problem and tested it in a game im working on, and i fixed your issue by changing void LateUpdate() to void FixedUpdate() here is the code! Hope i helped..
using UnityEngine;
public class CameraFollow : MonoBehaviour {
public Transform target;
public Vector3 offset;
public float smoothTime = 0.3f;
private Vector3 velocity;
private void LateUpdate()
{
transform.position = Vector3.SmoothDamp(transform.position, target.position + offset, ref velocity, smoothTime);
}
}

Related

Object won fall of the platform in Unity

So i made an ball(player) which moves forward on it's own with script. I want to make that ball act like a normal ball. when it riches the edge of platform it won't fall off. Basicaly it stops on the edge. Here's my image:
Here's my controller script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SwerveInputSystem : MonoBehaviour
{
private float _lastFrameFingerPositionX;
private float _moveFactorX;
public float MoveFactorX => _moveFactorX;
void Start(){
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
_lastFrameFingerPositionX = Input.mousePosition.x;
}
else if (Input.GetMouseButton(0))
{
_moveFactorX = Input.mousePosition.x - _lastFrameFingerPositionX;
_lastFrameFingerPositionX = Input.mousePosition.x;
}
else if (Input.GetMouseButtonUp(0))
{
_moveFactorX = 0f;
}
}
}
This is Second script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour{
private SwerveInputSystem _swerveInputSystem;
[SerializeField] private float swerveSpeed = 5f;
[SerializeField] private float maxSwerveAmount = 1f;
[SerializeField] private float verticalSpeed;
void Start(){
_swerveInputSystem = GetComponent<SwerveInputSystem>();
}
void Update(){
float swerveAmount = Time.deltaTime * swerveSpeed * _swerveInputSystem.MoveFactorX;
swerveAmount = Mathf.Clamp(swerveAmount, -maxSwerveAmount, maxSwerveAmount);
transform.Translate(swerveAmount, 0, 0);
float verticalDelta = verticalSpeed * Time.deltaTime;
transform.Translate(swerveAmount, verticalDelta, 0.1f);
}
}
EDITED: Adjusted the answer since we now have some source code.
You are positioning the player directly (using its transform) which will mess up the physics. The purpose of a rigidbody is to let Unity calculate forces, gravity, and so on for you. When you are using physics, and you want to move an object you have three main options:
Teleporting the object to a new position, ignoring colliders and forces like gravity. In this case use the rigidbody's position property.
_ourRigidbody.position = new Vector3(x, y, z);
Moving the object to the new position, similar to teleporting but the movement can be interrupted by other colliders. So, if there is a wall between the object and the new position, the movement will be halted at the wall. Use MovePosition().
_ourRigidbody.MovePosition(new Vector3(x, y, z));
Adding some force to the object and letting the physics engine calculate how the object is moved. There are several options like AddForce() and AddExplostionForce(), etc... see the Rigidbody component for more information.
_ourRigidbody.AddRelativeForce(new Vector3(x, y, z));
In your case you can simply remove the transsform.Translate() calls and instead add some force like this:
//transform.Translate(swerveAmount, 0, 0);
//transform.Translate(swerveAmount, verticalDelta, 0.1f);
Vector3 force = new Vector3(swerveAmount, verticalDelta, 0);
_ourRigidbody.AddForce(force);
We can get the _ourRigidbody variable in the Awake() or Start() method as normal. As you can see I like the Assert checks just to be safe, one day someone will remove the rigidbody by mistake, and then it is good to know about it...
private SwerveInputSystem _swerveInputSystem;
private Rigidbody _ourRigidbody;
void Start()
{
_swerveInputSystem = GetComponent<SwerveInputSystem>();
Assert.IsNotNull(_swerveInputSystem);
_ourRigidbody = GetComponent<Rigidbody>();
Assert.IsNotNull(_ourRigidbody);
}
One likely reason your Rigidbody is not being affected by gravity is due to having the field isKinematic checked to on. From the Rigidbody docs, when toggling on isKinematic,
Forces, collisions or joints will not affect the rigidbody anymore.
The rigidbody will be under full control of animation or script
control by changing transform.position
As gravity is a force and no forces act on the object when this setting is checked, your object will not fall when it is no longer on the platform. A simple solution is to uncheck this box.

Struggling to get my animations to work on my first game

I am trying to make my first game and have been struggling to get my animations to work.
I have been following along with a YouTube course and when it came to coding the animations on Unity i cannot seem to get it to work.
Please can someone who understands coding and Unity have a look at the following screenshots and help me out.
This is my code for my game:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public float moveSpeed;
private Vector3 input;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Verical"));
Rigidbody.AddForce(input * moveSpeed);
}
}
I cannot get the white dot next to my Player Control script to light up and it will not work.
Any help is appreciated, thanks.
If you are able to change the script, then this is how I would do it:
Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody>();
}
void Update()
{
float speed = 10f;
float x = Input.GetAxis(“Horizontal”) * speed * Time.deltaTime;
float z = Input.GetAxis(“Vertical”) * speed * Time.deltaTime;
rb.AddForce(x, 0f, z);
}
And freeze rotation along the x and a axis to not fall over. You can do this in the rigidbody component.

Trying to stop the momentum when re spawn

I have looked around the web for answers but can't find a working one.
I have tried changing the code and I am pretty sure it's a very easy noob mistake as this is my first game.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class respawn : MonoBehaviour
{
[SerializeField] private Transform player;
[SerializeField] private Transform respawnPoint;
private Rigidbody Rigidbody;
void FixedUpdate()
{
if (player.position == respawnPoint.position);
{
GetComponent<Rigidbody>().velocity = 0;
Rigidbody.angularVelocity = 0;
}
}
private void OnTriggerEnter(Collider other)
{
player.transform.position = respawnPoint.transform.position;
}
}
The very first thing you want to do is to look at the Unity error console. Your code throws multiple errors, they will appear in red. Double-click on an error to be taken to its line in your code.
Also, try get a good editor, like VS Code, as it will help you find issues immediately by adding red wavy underlines. With above two approaches in hand, you will be able to find ~99% of your issues yourself the next time, and then can ask in forums for the remaining 1%.
Let's go through your code step by step:
private Rigidbody Rigidbody;
In Unity you normally want the type in upper case Rigidbody, but the variable name in lowercase rigidbody (even though the C# coding conventions suggest uppercase properties). Either way, don't use the same name as the type, so write:
private Rigidbody rigidbody;
or e.g. (I'm now omitting the default private, though you may also prefer to keep it, and I use a shorter variable name, and clarify its start value):
Rigidbody body = null;
In the following code:
GetComponent<Rigidbody>().velocity = 0;
... you first of all get the rigidbody component again. This isn't needed if you got it once in start (and for repeated usage, can lag), so do it like this:
void Start()
{
rigidbody = GetComponent<Rigidbody>();
}
And secondly, you assign a 0, but you want to assign new Vector3(0f, 0f, 0f), or just
rigidbody.velocity = Vector3.zero;
rigidbody.angularVelocity = Vector3.zero;
Lastly, you write
player.transform.position = respawnPoint.transform.position;
... but player and respawnPoint are already transforms, so you can use the simpler
player.position = respawnPoint.position;
Good luck!
When you enter the Trigger you will be teleported to the respawn position, but you cannot depend on FixedUpdate running on that exact pixel of the respawn position.
The most straigh forward answer is to, well, do the code as you would describe the issue: "When you enter a trigger, set the position to the respawn position and set velocity to 0":
I would change the entire script to:
public class respawn : MonoBehaviour
{
[SerializeField] private Transform player;
[SerializeField] private Transform respawnPoint;
private Rigidbody rigidbody;
void Start()
{
rigidbody = GetComponent<Rigidbody>()
}
private void OnTriggerEnter(Collider other)
{
player.position = respawnPoint.position;
rigidbody.velocity = Vector3.zero;
}
}
and don't forget to populate the player and respawnPoint values in the inspector.
Also, keep in mind that the current code is prone to errors, if you have other objects moving around. Right now, if ANY object enters the Trigger the PLAYER position will be reset. You could fix this with check for player
private void OnTriggerEnter(Collider other)
{
if (other.transform == player)
{
player.position = respawnPoint.position;
rigidbody.velocity = Vector3.zero;
}
}

Platformer jitter from two boxcollider

I have made a platform for my player to walk on, which is a bunch of squares with BoxColliders attached, but when the players boxcollider runs on top of the platform, it creates a subtle jitter. I have tried adding a CircleCollider to the player but this does not fix the problem. Any ideas?
public class PController : MonoBehaviour {
private Rigidbody2D rgdby;
public float moveS;
void Start () {
rgdby = GetComponent<Rigidbody2D> ();}
void Update (){
if(Input.GetAxisRaw("Horizontal")>0f){
rgdby.velocity = new Vector3 (moveS, rgdby.velocity.y,0f);
}
else if (Input.GetAxisRaw("Horizontal")<0f){
rgdby.velocity = new Vector3(-moveS, rgdby.velocity.x,0f);}
else{
rgdby.velocity = new Vector3(0f,rgdby.velocity.y,0f);}}
}
The above is attached to the character
I would like to mention 2 possible fixes.
Update your velocity of the rigidbody inside a Fixed Update.
And try multiplying your velocity with Time.fixedDeltaTime or Time.deltaTime.

Unity camera following rolling ball. No rotation and no moving in Z-axis on camera

So, i'm building a 3D runner and i've got a lot of problems making the camera following the ball. I've been on google for a few hours and can't find anything that's not outdated or fills in the things I need. I want a camera that follows my ball but goes straight in the X-axis. When there are the stairs the camera needs to follow on Y axis.
I just don't want my camera to rotate (since my object is a rolling ball) and to move in the Z-axis.
var myPos : Vector3;
var myPlay : Transform;
function Update()
{
transform.position = myPlay.position + myPos;
}
This is what I already have. It doesn't rotate, but it follows on the Z-axis. I don't want that.
http://prntscr.com/9pmypz This is what it looks like in the Inspector.
As per Unity3D's Roll-A-Ball tutorial:
using UnityEngine;
using System.Collections;
public class CameraController : MonoBehaviour
{
public GameObject player;
private Vector3 offset;
void Start ()
{
offset = transform.position - player.transform.position;
}
void LateUpdate ()
{
transform.position = player.transform.position + offset;
}
}
I can't comment #HDL_CinC_Dragon answer because of my low reputation, but I wanted to add that using the public access modifier is a really bad habit. Instead you should use the private access modifier with the SerializeField attribute on the field, like this:
public class CameraController : MonoBehaviour
{
[SerializeField]
private GameObject player;
private Vector3 offset;