Unity player collision with horizontal small colliders - c#

I know the title isnt very explanatory, but here's my problem:
I have a player (merely a cube with a rigidbody, a collider and a movement script), and I have a floor made of small 1 by 1 by 1 cubes (cubes with box colliders).
For some reason unknown to me, when my player cube falls and tries to collide horizontally with the floor, he just phases through... But want him to get blocked by the cubes just like it does vertically. Any help would be greatly appreciated ;)
heres how the scene looks like
heres a cube object
heres the player object
Here's a gif of the player going through the floor
Here's my c# player movement script (I know its very bad, but I prefer to put this here just in case its linked to my problem) :
void ApplyMovement()
{
transform.position += new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
}
If you need any more info to help me just tell me, I'll provide it as fast as I can.

The value of
new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"))
is framerate-dependent. This means the faster the framerate the faster your object will move. This is usually not what you want. Instead use Time.deltaTime
// Adjust the speed in the inspector
public float speedMultiplicator = 1;
//...
new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")) * speedMultiplicator * Time.deltaTime
to get a framerate-independent movement. Also see the example in Input.GetAxis.
When dealing with RigidBody never change the transform.position (and rotation) directly!
If you would want to make the RigidBody jump to a certain position rather use
rigidBody.position = transform.position + ...;
However what you want is a smooth movement in order to keep the collision detection intact. So you should use RigidBody.MovePosition instead
rigidBody.MovePosition(transform.position + ...);
You don't have to deal with force etc.
Also add a RigidBody component to the floor objects. Even ifnthe object is not moving this improves the collision detection (at the cost of performance in the Physics engine ofcourse). And since the objects are not supposed to move set
isKinematic -> true
use Gravity -> false
you can also set freeze position and freeze rotation.
On both floor and player objects set Collision Detection -> Continous Dynamic. This improves the collision detection and looks for collisions also between frames.
Be aware, however, that dynamic detection is quite expensive so use it only if there is still trouble with too fast objects.
On the player you might want to also use interpolate as well.
Finally
Note that continuous collision detection is intended as a safety net to catch collisions in cases where objects would otherwise pass through each other, but will not deliver physically accurate collision results, so you might still consider decreasing the fixed Time step value in the TimeManager inspector
to make the simulation more precise, if you run into problems with fast moving objects.
For more information see the RigidBody manual and the Colliders manual

I recreated the scenario you described on my end. I put your "ApplyMovement" code in "Update". I was basically able to reproduce your results.
It seems to me that the issue might be Freezing Position X/Z on the Player. I think since you are doing that, you're telling the Rigidbody component that it is not allowed to modify the X/Z positions of the objects as part of it's collision resolution and physics simulation. When I turn those two off, I get results that are (I think) closer to what you're looking for.
One note: your "ApplyMovement" code is frame-locked, meaning your player will move at different speeds at different frame rates. To solve this, you'd need to multiply your Input.GetAxis values by Time.deltaTime.
Also, if your player moves too fast, it'll still be able to pass through collisions and cause odd behavior, so be sure to limit the max movement rate of the player to some reasonable value.

You should be applying a force to the Rigidbody of the character instead of directly manipulating the transform.position (this is preventing the physics engine from resolving the collisions). You're also freezing the X and Z position on the Rigidbody; you don't want that because it entirely prevents the Rigidbody from manipulating those values.
Instead of transform.postion += ... first get a reference to the Rigidbody somewhere in your script (best done in an Awake() method):
private Rigidbody _body;
private void Awake() {
_body = GetComponent<Rigidbody>();
}
Then make sure the vector built from your inputs is being applied to the object's "movement," not its position:
Vector3 inputVector = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
// You can multiply this vector by a float to adjust "speed"
_body.ApplyForce(inputVector, ForceMode.VelocityChange);
Finally, you should read up on the different ForceMode options and decide which one fits your preferences: https://docs.unity3d.com/ScriptReference/ForceMode.html
Don't forget this should happen in a FixedUpdate(), not an Update() (all physics operations should be done in FixedUpdate())
As a side note, there is also the possibility your rigidbodies still up moving too quickly and passing through each-other. Even when you're using forces and velocities, this is possible so if your run into this case down the line, investigate Collision Detection Modes. TLDR; they're settings for performance vs accuracy trade-offs.

Related

From to Rotation Glitching My Character Controller

So I am making a character controller which uses Quaternion.FromToRotation to align the player with the gravity center in this piece of code:
this_body.transform.rotation *= Quaternion.FromToRotation(this_body.transform.up,gravity_up);
And when I am on certain parts of the sphere planet it starts flipping out everywhere, like in this video, and I don't know how to remedy this, although maybe the gravity implementation could be the problem, or the character controller, although I think using relative force should not mess with it.
Gravity Implementation:
float distance = direction.magnitude;
float forceMagnitude = G * (obj.GetComponent<MultiAttractor>().rb.mass * rb.mass) / Mathf.Pow(distance, 2);
Vector3 force = direction.normalized * forceMagnitude;
rb.AddForce(force);
My character controller script is a bit long so I don't think I should bore you with it, although if needed I could provide it.
This is for anyone who is having issues with using Quaternion.FromToRotation with a rigid body character controller:
I did not dig much into your problem but you are manipulating the rotation directly in the code with Quaternion.FromToRotation and also with physics. I think you need to stick to one of the two, because using both might lead to unexpected behaviours. If you introduce a "raw" rotation modification, the physics engine deals with it. – rustyBucketBay
Basically just use physics rotation like Rigidbody.rotation for rotating things like Transform.Rotate or if you want to rotate physics objects like you are adding force, but instead of moving things it rotates things, then use Rigidbody.AddTorque, or just don't use any physics rotations with other types of rotation as it can cause problems, as stated by rustyBucketBay

C#/Unity Camera Follow Jitter due to Time.deltaTime

Game: In a simple 2D Portrait Game made in Unity, I have a GameObject (Player) that has a fixed location and which is moving upwards. The Camera follows the Player and animated Obstacles are spawning from time to time moving left to right. The attached Screenshot shows the Scene.
The Problem:
The Movement is not smooth, as it seems like the Player is jittering. I think I already identified one of the causes: Big variation of Time.deltaTime. Average value is 0.0167, but I had variations. Minimum was 0.00177, maximum value was 0.2249519.
Settings:
Target Framerate is 60. I use Unity 2019.4.2f1 and as build target an iPhone X with iOS 14.2.
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;
void LateUpdate()
{
FollowVector = Player.position - new Vector3(0, -4.0f, 10);
transform.position = Vector3.Lerp(transform.position, FollowVector, Time.deltaTime * 4f);
}
}
Note: I need to use Lerp, because the Player may lower or increase the speed for one second, then the camera gently moves to the new position, before changing back. For the Obstacles I don't have a Script. They are moving, by using the Animation Component. For the Obstacles I only loop a change of the x value of the position.
My alternative solutions:
1. Changing the value for Time.deltaTime to a constant value of 0.01666667f:
void Update()
{
transform.Translate(0,speed*0.01666667f,0);
}
This makes the Player Object jitter a lot in the Unity Editor but only a little on the device
2. Using Fixed Update both for the Camera Follow and the Player Movement
This makes the movement and camera follow perfectly smooth, but the animated objects jitter a lot. I know Unity wants to adress the deltaTime issue in one of the next updates. But there should be a solution for my problem, so did anybody have a similiar problem, which could be solved? I prefer the 2nd alternative, because the movement looked really smooth and nice, so can I somehow make the animation part of "fixedUpdate"?
The variation in the 'deltaTime' is to be expected.
The variation is large on the PC because you are running on a complex computer with a complex operating system and lots of other applications running simultaneously, each with a multitude of threads, which every once in a while want to do some work. Thus, the scheduler of the operating system cannot guarantee that you are going to get a time slice at the precise moment that you want it in order to render your next frame.
The variation is smaller on the mobile device because it is a much simpler machine with a lot less going on, so the scheduler is able to give you time slices close to the precise intervals that you are asking.
You are already taking this variation into account when you do
transform.Translate( 0, speed * Time.deltaTime, 0 );
This is a fundamental technique in game development: the frame rate is never constant, so the distance by which you must move an object on each frame depends on the precise amount of time elapsed between this frame and the previous frame.
So, that part is fine.
Your problem lies in
transform.position = Vector3.Lerp( transform.position, FollowVector, Time.deltaTime * 4f );
Here you are passing Time.deltaTime * 4f for parameter t of Vector3.Lerp(). I have no idea what you are trying to accomplish, but the number you need to pass there needs to be a gradual transition between 0 and 1, and instead you are passing a randomly varying number of seconds multiplied by some magic constant 4. This does not look correct.
A couple of options that I can think of:
Always use 0.5 for t so that the camera always rushes to the right position and then slows down as it gets closer to it.
Calculate a separate speed vector for the camera, then move the camera using a translation just as you do for the player.

RigidBody2D AddForce Not Adding Acceleration

I'm trying to add acceleration to an object with a RigidBody2D component using AddForce, but all it seems to do is add a fixed velocity instead.
Here are the RigidBody2D settings:
For testing I've modified the Update function to allow me to add forces and report the object's velocity periodically:
void Update()
{
time += Time.deltaTime;
if (time > 0.5)
{
Debug.Log("Velocity magnitude = " + rigidbody2D.velocity.magnitude);
time = 0;
}
if (Input.GetKeyDown(KeyCode.Q))
{
rigidbody2D.AddForce(Vector2.right);
}
}
What I see is that every time I press Q, the velocity magnitude increases by a fixed 0.02.
I.e. first it doesn't move at all and the velocity is 0, then after pressing Q the velocity magnitude changes to 0.02 and stays at 0.02 while the object trudges slowly to the right. Pressing Q again increases it to 0.04, then pressing once more increases it to 0.06 and so on.
These are results from two days ago. I did the experiment again today and got different velocity increments but the same behavior otherwise.
The velocity changes only when I add a force.
If I added a force of magnitude 1 to an object at rest with a mass of 1 then its velocity would increase by 1 in magnitude every single unit of time (which I think here is seconds).
Instead it's staying fixed.
Using ForceMode2D.Impulse increases the velocity increments from 0.02 to 1, but the behavior stays the same - no acceleration, only one-time increments in speed.
What am I doing wrong?
I've tried looking for similar posts and for the problem in general but the only things I found were either irrelevant or asking the opposite (how to stop acceleration from occurring).
Any help would be appreciated.
The Unity version is 2019.1.1f1.
TL;DR
What you are doing wrong is that you are expecting the wrong physics behavior from the apply force function. That function does what it says, it applies force. It changes the object velocity instantaneously adding to it. The force mode for 2d bodies only tells the engine to consider the object's mass or not.
The problem is the naming Unity uses, AddForce doesn't "add" the force, it just applies the force for a single frame. In the following frames, all forces are zero again. If you want to keep the force, just create your own vector in your script, modify it, and apply it to the object every frame using AddForce.
how are you?
I have created a sample project to reproduce your issue but I couldn't reproduce the velocity staying fixed as you said. I'm not sure how you set up your scene so I made some assumptions. You probably have disabled either gravity on your object or friction, since you are reporting that the velocity is increased.
Acceleration, on the other hand, is a constant force being applied, think of it. If your car is still, and you push it for a short amount of time, the car will move then stop. If you keep pushing on the other hand, adding more and more force, the car will move faster and faster. Now think about your environment, you have a frictionless object. Every time you press Q you add a small force to it. It moves to the right a bit faster but with a constant speed (there is no force to change its velocity).
Here is what you'd want to do. Instead of adding the force only in the frame you pressed Q, add while you are pressing Q. This is what you want to do:
private void FixedUpdate()
{
time += Time.deltaTime;
if (time > 0.5)
{
Debug.Log("Velocity magnitude = " + rigidbody2D.velocity.magnitude);
time = 0;
}
if (Input.GetKey(KeyCode.Q))
{
rigidbody2D.AddForce(speedMultiplier * Time.fixedTime * Vector2.right, ForceMode2D.Force);
}
}
Another problem is the naming Unity uses, AddForce doesn't "add" the force, it just applies the force for a single frame. In the following frames all forces are zero again. If you want to keep the force, just create your own vector in your script, modify it, and apply it to the object every frame using AddForce.
Also, see that I changed Update to FixedUpdate? In Unity, you are recommended to apply all physics changes in that method instead. Update runs as much as it can (once every frame if possible), fixed update instead runs only after the physics thread is done. This means you are not spending CPU time telling the object to move every frame, and instead you are waiting for the physics to be synchronized.
I don't think that's going to add enough force to the object to get it into motion. Normally you need to multiply your direction by a "force" multiple. Try something like rigidbody2D.AddForce(Vector2.right * 1000);. That is, intentianally, probably way too much force but at least you'll know it's moving.

Moving a RigidBody2D a specific amount of units

In my 2D side-scrolling game I move my character using the built-in physics engine by manipulating the rigidbody.velocity.
I would like to add some sort of dodge (roll) ability, where the character moves 3 units in its direction.
Here is the code I used:
void FixedUpdate() {
if (Input.GetKeyDown(KeyCode.A) ) {
Vector2 pos = rb.position;
pos.x -= 5;
rb.MovePosition (pos);
}
}
This method works but the character kind of jumps to the position rather than moving to it (Lerping?) and also doesn't detect collisions despite the body type being dynamic.
Then I tried this:
if (Input.GetKeyDown(KeyCode.A)) {
rb.AddForce(new Vector2(-50, 0));
}
I found the AddForce way isn't accurate at all.
Is there a proper way of doing this?
Maybe you could change the Transform.pos inside Vector2.Lerp to make it look smooth? (Sorry, not enough experience with 2D in unity.)
Just increase rigibody.velocity for a set time. Your chararter object could then play a fitting aniamtion. If The player should not be able to cancle midrole jsut block the controls for that time.

Rigidbody not acting as expected

For the past few days I have been working on some custom car physics as a coding exercise.
What my ultimate goal is to have some semi-realistic car physics something in between the quality of the older GTA games and the recent GTA 5.
Now what I got so far is a quite intricate process which eventually gives me a float which is the exact speed I want the car to go until the next frame, so far I have used the following code to do that;
this.transform.Translate (0, 0, speed * Time.deltaTime);
However because I want to use the Unity build in physics for collision detection I realised this wouldn't work because transform.Translate (as far as I know) literally places the object at that position, thus the object could (if going fast enough) suddenly be halfway stuck through a wall or just completely ignore the collision and appear on the other side of the wall. Now instead I decided to do this:
rb.velocity = transform.forward * speed;
To quickly note, I am doing both of these in my FixedUpdate and I am currently only using the second example (or at least trying to use it and am miserably failing at it). Due to it being in the fixed update I should be able to at least test it to a certain extend without Time.deltaTime usage, which is why you aren't seeing that in the second example right now.
To continue my story, for some reason when I set the velocity of the rigidbody instead of using transform.Translate my collision acts really strangely. The car becomes all floaty and nudges forward (stands on its nose) when I hit the wall, I have no clue what could be causing this seeing as I am using my own gravity (the gravity from the original Rigidbody is turned off in favor of my own custom gravity, which does result in a downward rigidbody force) and the drag, and angular drag of the rigidbody have been turned down to 0.
Basically my question is do any of you guys have an idea of what could be causing my rigidbody to be reacting in such a manner, literally the only difference between my normal code and the code that is acting up is that single line change.
I've looked in to using rigidbody.AddForce() instead but that just doesn't seem to do anything at all and on top of that the whole reason why I am writing my car script is to determine the velocity the object should be moving at thus making something like rigidbody.AddForce() which adds it to the velocity of the car more or less redundant and shouldn't be necesarry.
The only reason why I'm even using a rigidbody in the first place is so I can do two things: 1. Easy collisions. It means I can add simple forces such as gravity to it and not have to worry about it going through the floor. 2. easy rotations when affected by physics such as collisions.
If anyone has any ideas on how to do these two things in a custom script I'd much rather do that because as much as I like unity the Unity rigidbody physics are practically worthless in my eyes, however a must have because I can't write my own custom rigidbody and I can't find the source code of the Unity Rigidbody either. What I'd rather have is a stripped down version of the rigidbody which allows for easy collisions and easy rotation but without all the stuff like the build in drag or velocity because these are the exact things I want to be able to control myself and have been able to control myself so far when I use transform.Translate, but I lose this control when I have to use rigidbody.velocity.
according to the documentation you shouldn't use rb.velocity to change the velocity regularly - it could result in unrealistic physics
http://docs.unity3d.com/ScriptReference/Rigidbody-velocity.html
instead use rb.addforce
http://docs.unity3d.com/ScriptReference/Rigidbody.AddForce.html
hopefully that will solve the issue!
Replace the Translate with the following:
rb.MovePosition(transform.position + transform.forward * (speed * Time.deltaTime));
MovePosition basically acts as a translate (if you do it like this) except it also counts collisions in to it.
If you want super realistic 3D car physics, should look into ready assets like:
Edy's Vehice Physics https://www.assetstore.unity3d.com/en/#!/content/403
Also from Unite2015 talks, see example project: "EasySuspension" to build sample 3D car by script:
http://bit.ly/1y8ucNW (from video: https://youtu.be/WGvuP6vV6j4?t=17m8s )
Or is the game top down 2D game? (like early GTA's)

Categories