Platformer jitter from two boxcollider - unity3d

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.

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.

Why more balls are instantiating?

I'm making a game in unity where the user drags to shoot a ball at some objects at a distance. So far I have this DragAndShoot script:
//using System.Collections;
//using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(Collider))]
public class DragAndShoot : MonoBehaviour
{
public Transform prefab;
private Vector3 mousePressDownPos;
private Vector3 mouseReleasePos;
private Rigidbody rb;
private bool isShoot;
void Start()
{
rb = GetComponent<Rigidbody>();
}
private void OnMouseDown()
{
mousePressDownPos = Input.mousePosition;
}
private void OnMouseUp()
{
mouseReleasePos = Input.mousePosition;
Shoot(mouseReleasePos-mousePressDownPos);
}
private float forceMultiplier = 3;
void Shoot(Vector3 Force)
{
if(isShoot)
return;
rb.AddForce(new Vector3(Force.y,Force.x,Force.z) * forceMultiplier);
isShoot = true;
createBall();
}
void createBall(){
Instantiate(prefab, GameObject.Find("SpawnPoint").transform.position, Quaternion.identity);
}
}
As you can see, I made the function createBall() in order to respawn a ball prefab at the position of the game object SpawnPoint. When I run the game, the first ball shoots fine. And another ball respawns.
Issue: when I shoot the second ball and it moves, one more ball seems to have appeared at the second ball somehow, and it moves as well. Not sure why this is happening and how to fix it - can someone pls help? Thanks.
The problem is that you need to Destroy() the game object you threw first. Since you are just bringing the objects back when click down again, here is what you should do:
Make it so that it destroys the old object. Because you just keep instantiating the object, then when you throw it again it throws the old one too. If you understand what I mean, then hopefully, you can turn this into what you want. (It wasn’t exactly clear what your game was; this is what I interpreted)

How to call a method every time, when player stay at any collider?

I have a game like CubeSurfer. When player goes through an collectable, two methods are called (for "jumping" and creating a cube under player). But, when player goes through second, or third collectable, nothing happens. I tried to attached script to collectable, and tried to put the method "OnTriggerEnter" in the body of methods "Start" and "Update". But it doesn't work.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCollider : MonoBehaviour
{
[SerializeField] Collider player;
[SerializeField] GameObject destroyIt;
[SerializeField] GameObject objToClone;
[SerializeField] Transform rootObjInScene;
Transform curParent;
Vector3 posOffset, posPlayer;
float distance = 1f;
private void OnTriggerStay(Collider player)
{
PlayerJumping();
CreateAnother();
Destroy(destroyIt);
}
public void PlayerJumping()
{
posPlayer = Vector3.up * distance;
Vector3 playerPos = rootObjInScene.position + posPlayer;
rootObjInScene.transform.position = playerPos;
}
public void Awake()
{
curParent = rootObjInScene;
posOffset = Vector3.down * distance;
}
public void CreateAnother()
{
Vector3 newPos = curParent.position + posOffset;
GameObject newObj = Instantiate(objToClone, newPos, Quaternion.identity, curParent);
curParent = newObj.transform;
}
}
You should also check your Rigibody collision detection mode in the inspector.
By default, this is set to Discrete, but if your object is fast-moving, you should set it to Continuous or ContinuousDynamic, otherwise the collisions won't be registered because the object is moving too quickly.
These are a little bit performance intensive, so I'd still recommreading up on the Unity documentation or digging through a couple of good articles to know what's best for you :)
You shouldn't call OnTriggerEnter explicitly (in your Update()), it's an event message and gets called automatically by unity when you enter a Collider marked isTrigger.
You can use OnTriggerEnter only if your collider is marked isTrigger, if you want to get a collision with a Collider that is not explicitly a trigger, you use OnCollisionEnter
To execute a method repeatedly while touching a Collider use OnCollisionStay, while touching or inside a Collider with isTrigger use OnTriggerStay
OnCollisionStay
OnTriggerStay
You can use OnCollisionStay or OnTriggerStay
void OnCollisionStay(Collision collisionInfo)
{
//Do something when collisionInfo.gameObject stay in this.gameObject collider
}

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;
}
}

Smooth Camera Follow in Unity for 2D Platformer

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);
}
}