My game is a topdown 2D game, and when the player collides with another object while it is moving the player starts bouncing off. I've tried using a 2D physics material with 0 bounciness and it doesn't solve the problem. I think it has something to do with the way my movement code. I tried using Rigidbody.MovePosition, but it didn't work and my player was glitching out. This is my movement code.
float horizontal = Input.GetAxis("Horizontal") * moveSpeed * Time.deltaTime;
float vertical = Input.GetAxis("Vertical") * moveSpeed * Time.deltaTime;
transform.Translate(new Vector2(horizontal, vertical));
Try using the MovePosition method on your Rigidbody inside of FixedUpdate instead of changing the position of the player's transform. If that does not solve the issue, try also changing the collision detection mode of the player's rigidbody to continuous.
When working with physics and Rigidbodies in Unity, you would want to do most of the physics related things in the FixedUpdate method. This method runs in sync with Unity's physics loop and all the physics calculations are done right after all of the FixedUpdate methods have been called. This allows for smooth looking interactions and physics.
Related
Hello all, I'm very new to and very confused by Unity.
I'm creating a top-down, gravity-free test game, similar to PacMan (i.e. think of the movement of characters in straight lines).
Currently, I'm trying to move an object in straight lines (without curvature) (see image).
My GameObject has RigidBody2D attached, as well as Linear, Angular and Gravity set to 0.
I'm currently controlling my GameObject by adding force:
private Rigidbody2D _playerRB2D;
public float _speed;
private void FixedUpdate()
{
float moveHorizontal = Input.GetAxis("Horizontal");
float moveVertical = Input.GetAxis("Vertical");
Vector2 movement = new Vector2(moveHorizontal, moveVertical);
_playerRB2D.AddForce(movement * _speed);
}
The idea is that the game object won't get to slow down, so is constantly in motion (in straight lines). Collision with objects is obviously important too!
Any help or information to look at will help a lot, thank you!
Unity has a built-in physics engine that calculates movement based on velocity (and collisions, etc.) By using Rigidbody2D.AddForce, you are adding to your rigidbody's velocity. This means that if you press the up arrow and then the right arrow, the velocity from pressing the up arrow remains, causing a diagonal velocity and curved path. If you want straight lines, you can use Rigidbody2D.velocity or just use Transform.translate.
_playerRB2D.velocity = movement * _speed;
Edit: You said that collisions were important, so keep the rigidbody
or remove the rigidbody2D component and use
transform.Translate(movement * _speed);
The idea is basically to reset the force being applied on the rigidBody2D on each changed direction.
In fact, you would have to test if the direction input from horizontal is greater than vertical for x axis, and the inverse for y axis , and thus if it is true, change the opposite to 0f.
You would have normally:
Vector2 movement = new Vector2(moveHorizontal < moveVertical ? moveHorizontal: 0f, moveVertical < moveHorizontal ? moveVertical: 0f);
_playerRB2D.velocity = movement * speed;
Edit: By testing the input value, you can move your RigidBody2D with a analogic controller, and thus being straight as you wished !
I'm working on a playercontroller, very basic and am encountering loads of stutter when using the rigidbody player. I also have a character controller player which runs very smooth, both tests are at high fps 600 ish (v-sync turned off). I am using the freelook camera of unity's cinemachine in both cases and set the CinemachineBrain update mode to fixed for the Rigidbody scene. I have tried turning on Interpolation on the Rigidbody and chaging the FixedUpdateTimestep (which I try to avoid), but I am wondering if it has anything to do with the way I move my Rigidbody? Below is a video to show the issues, make sure to watch it fullscreen and pay attention to the blockstairs (Incase it's unclear the red player is Rigidbody based and the green one uses a CharacterController component). You can see a huge difference in smoothes between the scenes.
My Rigidbody movement code (Very simple);
void Update()
{
_isGrounded = Physics.CheckSphere(_groundChecker.position, GroundDistance, Ground, QueryTriggerInteraction.Ignore);
_inputs = Vector3.zero;
_inputs.x = Input.GetAxis("Horizontal");
_inputs.z = Input.GetAxis("Vertical");
if (_inputs != Vector3.zero)
transform.forward = _inputs;
}
void FixedUpdate()
{
_body.MovePosition(_body.position + _inputs * Speed * Time.fixedDeltaTime);
}
Video showcasing the issue
I believe if you want to move rigid bodies directly you will need to turn on the kinematic flag for it. Otherwise all other rigidbody and forces that are applied to it through your movement will affect it and cause jitter or strange behavior.
See this page: https://docs.unity3d.com/ScriptReference/Rigidbody-isKinematic.html
In my game I want the character to be able to have a pickaxe or weapon that can rotate around the player but when I do so it goes through the objects and is very glitchy.
I want it to still follow the mouse (which is invisible) and still stop when it has a collision. My code right now is just pretty standard code for mouse rotation and its attached to an empty gameobject which is the parent of the pickaxe/weapon
//rotation
Vector3 mousePos = Input.mousePosition;
mousePos.z = 5.23f;
Vector3 objectPos = Camera.main.WorldToScreenPoint(transform.position);
mousePos.x = mousePos.x - objectPos.x;
mousePos.y = mousePos.y - objectPos.y;
float angle = Mathf.Atan2(mousePos.y, mousePos.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(new Vector3(0, 0, angle));
Whenever you have a GameObject that you want to be physics enabled, you don't move it directly. You add a Rigidbody and use RigidBody.MoveRotation to rotate your GameObject. RigidBody has its set of movement and rotation methods that take into account collisions. Moving the Transform directly will cause problems.
This can still cause problems in some situations. If you're still experiencing physics weirdness then you can eliminate them by using a "physically correct" solution and use Rigidbody.angularVelocity. Based on the angle you can set the velocity to either rotate the object right or left until it faces the way you want.
Essentially the physics system hates teleportation. Instant movements and instant rotations are basically teleportation to it. So there's a hierarchy of how "physics system friendly" some actions are. And they go like this:
Adding Force to the RigidBody
Adding Velocity to the RigidBody
Moving the GameObject through appropriate RigidBody methods.
Moving the GameObject through Transform.
I have a Rigidbody attached to my character controller and my enemies. I want the enemies to be able to surround me and have me trapped without me being able to move, so I set the mass property accordingly.
There's just a small problem - if I don't set my mass high enough, the moment the enemies collide with me, my player will go flying into the air. If I don't set my enemies' mass high enough, I will be able to walk right through them. How can I fix this issue? Here is the movement code for the player:
using UnityEngine;
using System.Collections;
public class CharController : MonoBehaviour {
public float speed;
void Start () {
Cursor.lockState = CursorLockMode.Locked;
}
void Update () {
float translation = Input.GetAxis ("Vertical") * speed;
float strafe = Input.GetAxis ("Horizontal") * speed;
translation *= Time.deltaTime;
strafe *= Time.deltaTime;
transform.Translate (strafe, 0, translation);
if (Input.GetKeyDown ("escape")){
Cursor.lockState = CursorLockMode.None;
}
}
}
The problem here is that you're using Transform.Translate() to move your player object. As a result, the player is being moved into clipping with your enemy objects in between physics calculations - so when the next physics calculation comes around, there will be a massive repulsing force to correct this. This is what's sending your player flying.
A better alternative is to use Rigidbody.AddForce() (or one of its variants) to indirectly move your player object. This allows the player object's movement to be taken into account during physics calculations, so it can collide with and be stopped by enemy objects before it starts clipping into them.
If you retrieve and store a reference to the player's Rigidbody in a variable, then you can replace Translate() with something like:
rigidbody.AddRelativeForce(strafe, 0, translation);
Hope this helps! Let me know if you have any questions.
Make sure IsKinematic is checked. UseGravity can be checked or not depend on your situation.
That way, you rigidbody will not be affected by force, collision or joint and is under full control of your script. But maybe they will lose the ability to detect collision as well but I'm not so sure, I haven't tested it yet.
If that was the case, uncheck the IsKinematic and instead, check FreezeRotation and FreezePosition as well. That way, you revoke control of the physics from affecting your position and rotation. You will manually manipulate position & rotation from your script (using CharacterController).
References:
https://docs.unity3d.com/ScriptReference/Rigidbody-isKinematic.html
https://docs.unity3d.com/Manual/class-Rigidbody.html
I'm still learning the basics so please be a bit gentle. I'm working on the movement script of a roll-a-ball game. I've got the rolling around working perfectly fine, but now I'm trying to add the ability to jump.
In my case the "player" is a basic Sphere. What I'm trying to accomplish is that when space is pressed, the ball leaps into the air in the direction it's currently rolling.
This is what I've tried myself, but gave very strange results:
float moveHorizontal = Input.GetAxis("Horizontal");
float moveVertical = Input.GetAxis("Vertical");
Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);
if (Input.GetKey("space"))
{
transform.position += transform.up * 20 * Time.deltaTime;
}
rb.AddForce(movement * speed); //rb = RigidBody
This resulted in the ball sometimes jumping in the wrong direction or simply just speeding into some direction without jumping at all. So obviously I'm getting closer, but not quite there yet. Could anyone explain what I'm doing wrong and how to fix it?
Not looking for a quick fix! Don't learn anything from that.
Have a try at this :)
if (Input.GetKey("space"))
{
rigidbody.AddForce(new Vector3(0, yourJumpForce, 0), ForceMode.Impulse);
}
You also might want to fiddle with the gravity settings in the rigidbody to get your desired jump as well!
EDIT Explanation:
I think it may be because you are applying you movement to your Rigidbody, but your jumping method to the Transform itself.
A Rigidbody is a physics component (see docs.unity3d.com/ScriptReference/Rigidbody.html), where a Transform is to do with position, rotation and scale.
A jump could be considered a physics problem - therefore altering the jump is to do with physics (Rigidbody), not the position (Transform). I tend to do all movement code with the Transform, as you are moving positions, and do all physics based work with the Rigidbody, as you are applying physics to the GameObject! :)
To add to the accepted answer: The jumping into random directions issue could have been caused by the transform.up. That vector is the up direction relative to your current transform. That's usually the same as the actual up direction, except if you rotate the game object. And as the object happens to be a rolling ball in this case, it's very likely that it's rotated.
You can fix it by using the global up direction instead - either by doing it like in the accepted answer or by using Vector3.up.