Unity 3D - Third Person character movement using rigidbody - c#

I am new to Unity trying to make my first game (a Third Person Shooter).
It's been now more than a week that I've tried again and again to get my character moving using a rigidbody component and NOT the Character Controller or the simple transform.Translate.
I have had about 30 web pages opened since a week browsing topics about it but I haven't found anything (almost made me feel like I am trying to do something impossible lol...).
So, I want to move my character just like in Splinter Cell Blacklist, and to have the camera with the crosshair controlled by the mouse (if I shoot, the character would rotate if not facing the target and then shoot).
For the movement, if it is not possible with the rigidbody then I'll use one of the others, it's just that I love the real feeling that the rigidbody has.
If there's even a tutorial that break it down to really understand, that would be great or just some code with comments (I have a C# background).
float moveSpeed = 6f; // Player's speed when walking.
float rotationSpeed = 6f;
float jumpHeight = 10f; // How high Player jumps
Vector3 moveDirection;
Rigidbody rb;
// Using the Awake function to set the references
void Awake()
{
rb = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
Move();
}
void Move ()
{
float hAxis = Input.GetAxis("Horizontal");
float vAxis = Input.GetAxis("Vertical");
Vector3 movement = new Vector3(hAxis, 0f, vAxis);
rb.position += movement * moveSpeed * Time.deltaTime;
}

My idea.
If you want the real feel, you need the rigidbody.addforce to your character at the proper part of the character body. Not the rigidbody.position.
Hope help.

Related

unity : rotating a gun 360 dgrees around the player in a 2d platfrom shooter

trying for 2 days to rotate a gun around a player in a 2d platfromer and i have 3 problems
1: the item or rotate uncontrolebly (my grammer isnt the best my mother language isnt even latin base)
around the player even if i dont move my mouse .or its rotate on its self like a wheel.
2:its seems phisycs some how work on the gun even though its dosnt has a rigibid body. givin in rb on kinimatic halped but not fully.
3: its rotate way to quickly . little movment will cause it to fly
4(bonus) the sqauer module i gave it strach and band in a really weird way.
heres the code:your text
[SerializeField] float fireRate = 0.3f;
[SerializeField] float rocketSpeed = 20f;
[SerializeField] GameObject rocketType;
[SerializeField] Transform firePoint;
Player player;
Vector3 mousePos;
Camera mainCam;
void Start()
{
player = FindObjectOfType<Player>();
mainCam = FindObjectOfType<Camera>().GetComponent<Camera>();
}
// Update is called once per frame
void Update()
{
mousePos = mainCam.ScreenToWorldPoint(Input.mousePosition);
}
private void FixedUpdate()
{
Vector3 aimDirection = mousePos - transform.position;
float aimAngle = Mathf.Atan2(aimDirection.y, aimDirection.x) * Mathf.Rad2Deg ;
// Quaternion rotation = Quaternion.AngleAxis(aimAngle, Vector3.forward);
// transform.rotation = rotation;
transform.rotation = Quaternion.Euler(0, 0, aimAngle);
// transform.RotateAround(player.transform.position, Vector3.forward, aimAngle);
}
here a picture of the componets:
enter image description here
wanted a gun obj to rotate around my charcter whan its move or still, wanted to shoot stuff while i jump.
Mathf.Atan2 returns the value in Radians, but Quaternion.Euler uses Degrees. You'll have to multiply the value by Mathf.Rad2Deg first.
It also sounds like the parent of the gun has a rigidbody which is causing it to Rotate. Remove the rigidbody you put on the gun and toggle on "Freeze Rotation" on the parent's rigidbody.

Rigidbody.MovePosition() behaving strangely

using UnityEngine;
public class ThirdPersonMovement : MonoBehaviour
{
Rigidbody rb;
private Animator animator;
public float speed = 5f;
void Start() {
animator = GetComponent<Animator>();
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
//Get player input based on world space.
float playerHorizontalInput = Input.GetAxisRaw("Horizontal");
float playerVerticalInput = Input.GetAxisRaw("Vertical");
//Get camera-normalized directional vectors
Vector3 forward = Camera.main.transform.forward;
Vector3 right = Camera.main.transform.right;
//Create direction-relative input vectors
Vector3 forwardRelativeVerticalInput = playerVerticalInput * forward;
Vector3 rightRelativeHorizontalInput = playerHorizontalInput * right;
Vector3 cameraRelativeMovement = forwardRelativeVerticalInput + rightRelativeHorizontalInput;
Vector3 movement = cameraRelativeMovement * speed * Time.deltaTime;
rb.MovePosition(transform.position + movement);
transform.forward = cameraRelativeMovement;
if (cameraRelativeMovement != Vector3.zero)
{
animator.SetBool("IsMoving", true);
}
else {
animator.SetBool("IsMoving", false);
}
}
}
I know similar questions have been posted before but I haven't been able to find a solution to what I'm experiencing.
I have the code above and it is linked to a character with a rigidbody component and 'is kinematic' checked. When I try to move, the character doesn't move for ages and then randomly jumps forward a random distance and doesn't do it again until I hit W again.
This has worked before when I used transform.Translate but obviously my character ran through the floor when the camera pointed down so I was trying to fix the issue.
A few things I notice about your code. You said this method used to work with transform.translate but not anymore, this tells me that your movement vectors are probably fine up until the point you changed them for this implementation (my guess is everything is the same except when you added tranform.position to your vector, since the function doesn't take speed, it takes position). You could try testing tranform.position + movement or just movement with a Debug.Log() statement, but that's probably not your issue.
Since you said this issue only started when you changed the function you use to move the player, I would try just inputting a non-changing Vector3 into the movement function: rb.movePosition(tranform.position + new Vector3(1,0,0)); or something like that, just to see if the movement function is even working.

Unity3D Player walking through and on the Stone

Hello guys my Player is walking on the Stone and through the Stone. The Player called Champ has a Box Collider and the Stone has a Mesh Collider. Also the Player has Rigidbody. I tried everthing i found but nothing helped me with my problem.
MovePlayer.cs Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MovePlayer : MonoBehaviour
{
Rigidbody rb;
public float speed = 10f;
private Vector3 moveDirection;
public float rotationSpeed = 0.05f;
void Start()
{
rb = GetComponent<Rigidbody>();
}
void Update()
{
moveDirection = new Vector3(Input.GetAxisRaw("Horizontal"), 0f, Input.GetAxisRaw("Vertical")).normalized;
}
void FixedUpdate()
{
rb.MovePosition(rb.position + transform.TransformDirection(moveDirection * speed * Time.deltaTime));
RotatePlayer();
}
void RotatePlayer()
{
if (moveDirection != Vector3.zero)
{
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(moveDirection.normalized), rotationSpeed);
}
transform.Translate(moveDirection * speed * Time.deltaTime, Space.World);
}
}
Player Settings in Inspector
Stone Settings in Inspector
Scene Preview
Thank you for help guys! :)
So guys i found out the Solution with the help of the guys posted above.
The problem was that my player speed was too high in the Code the speed was on float 10, but i changed the velocity in the Unity Inspector of Player to float 50.
So my first step to solve the problem was to set the speed down to float 10, but i still wanted to move with a speed of 50f...
The Solution for this problem was that in Unity 2020.3.24f1 and higher (probably lower) you can go to Edit>Project Settings>Physics and set the "Default Max Depenetration Velocity" to the speed you want the objects stopping and not going through. In my case i wanted to move with speed = 50f so i needed to change Default Max Depenetration Velocity to 50.
I hope i can help someone with this Answer in future!
Best Wishes
Max G.
Tested your code and collisions seem to be working fine on my end.
Tested it by adding the script to a GameObject with box collider and creating a small level using cubes. Also made a wall that I modified to use mesh-collider instead of box collider. Player collided normally with objects in the scene.
You should double check your Layer collision matrix from Project Settings > Physics whether you've set layers player and wall to collide.
You could also try adding new cube to the scene and setting its layer to wall to see if player collides with it. If it does then the there might be issues with the mesh of the stone.
If not then I would disable animator and Gravity Body components from the player to make sure they're not interfering with the collisions
Rigidbody.MovePosition basically makes the player teleport which can cause unexpected behaviors. It's generally recommended to use Rigidbody.AddForce instead. For precise movement ForceMode.VeloictyChange can be used.
public float maxVelocityChange = 5.0f;
void moveUsingForces(){
Vector3 targetVelocity = moveDirection;
// Doesn't work with the given RotatePlayer implementation.
// targetVelocity = transform.TransformDirection(targetVelocity);
targetVelocity *= speed;
// Apply a force that attempts to reach our target velocity
Vector3 velocity = rb.velocity;
Vector3 velocityChange = (targetVelocity - velocity);
velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
velocityChange.z = Mathf.Clamp(velocityChange.z, -maxVelocityChange, maxVelocityChange);
velocityChange.y = 0;
rb.AddForce(velocityChange, ForceMode.VelocityChange);
}
In this code you have applied motion twice and the problem is that transform.Translate is used. Remember that Rigidbody class methods are sensitive to colliders and recognize them, but transform is not the same and only applies a point-to-point shift. To solve the problem, I think you will not need a duplicate motion code with translate in the rotate section.
void RotatePlayer()
{
if (moveDirection != Vector3.zero)
{
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(moveDirection.normalized), rotationSpeed);
}
// removed translate
}

I have a cube that spins all over the place when I hit an object.(the camera and character spins) UNITY

I have a simple movement that relvolves around moving foward depending on where I look. The camera is made to follow the player. The problem I am havaing is that whenever I hit an object, my character(along with the camera) start spinning crazily all over the place. (I am new to coding)
Here is the code to the movement of where my character is facing :
public class Player : MonoBehaviour {
public float movementSpeed = 10;
public float turningSpeed = 60;
public Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody> ();
}
void Update() {
float horizontal = Input.GetAxis("Mouse X") * turningSpeed *
Time.deltaTime;
transform.Rotate(0, horizontal,0);
float vertical = Input.GetAxis("Mouse Y")* turningSpeed * Time.deltaTime;
transform.Rotate(vertical, 0, 0);
float movement = Input.GetAxis("Foward") * movementSpeed *
Time.deltaTime;
transform.Translate(0, 0,movement);
}
}
(Sorry for bad format)
The Mouse X just makes it so that it rotates on the x axis of mouse(same with y axis). The Foward is just the vertical input preset in unity.
Here is the code to the lookAt player :
public class LookAtCamera : MonoBehaviour {
public GameObject target;
void LateUpdate() {
transform.LookAt(target.transform);
}
}
Answer
I believe your rigidbody is being more heavily affected than what you desire by the bounce force occuring as you hit the object.
Possible solutions
Depending on which collider type acts as your legs, the weight of the objects involved, what behaviour you intend and more the solution can vary.
Possible solution 1:
One option is to freeze the rotation of your object on it's Rigidbody component, you can decide which axes to freeze rotation on. If freezed they can't be pushed by outside forces.
Possible solution 2:
If you wish the player to only be affected by your script you can set the rigidbody kinematic, meaning that it only is affected by scripts and animation. This is a contrast to being set to dynamic where other objects can affect it.
Possible solution 3:
Play around with the angular drag and mass of the rigidbody to slow down rotation.

horizontal movement in Unity

I'm very new in Unity and I'm trying to move a simple square on a classic 2D map (Super Mario like).
I use addForce to jump, it goes as planned.
But now, I'm trying to move my character horizontally.
First, I tried to use tramsform.translation(), I quickly notice that isn't the proper way, cause this method "teleports" the character, and if it moves too quickly, it can teleport behind a wall. I also try with addForce, but I want that my character has a constant speed, and it gives inertia, so it doesn't stop instantly when I release the key. I also try with .MovePosition(), but the character is shaking with this method (apparently, due to gravity).
So, whats the proper way to move a character (Rigidbody2D) horizontaly?
Here's my code with the different try:
using UnityEngine;
using System.Collections;
public class test : MonoBehaviour {
private Rigidbody2D rb;
public Vector2 velocity;
public float jumpforce;
// Use this for initialization
void Start () {
rb = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update () {
Debug.Log(velocity);
if (Input.GetKeyDown("space")){
rb.AddForce(new Vector2(0, jumpforce), ForceMode2D.Impulse);
}
if (Input.GetKey("a")){ // move to the left
rb.AddForce(-velocity * Time.deltaTime, ForceMode2D.Impulse);
//rb.MovePosition(rb.position - velocity * Time.fixedDeltaTime);
//transform.Translate(-velocity);
}
if (Input.GetKey("d")){ // move to the right
rb.AddForce(velocity * Time.deltaTime, ForceMode2D.Impulse);
//rb.MovePosition(rb.position + velocity * Time.fixedDeltaTime);
//transform.Translate(velocity);
}
}
}
Personally, I use a setup like this:
Rigidbody2D rb;
[SerializeField] [Range(0, 1)] float LerpConstant;
//Other stuff here
FixedUpdate() {
float h = Input.GetAxisRaw("Horizontal");
Vector2 movement = new Vector2(h, rb.velocity.y);
rb.velocity = Vector2.Lerp(rb.velocity, movement, LerpConstant);
}
Lerp simply means "take a Vector2 that is 'x' amount from A to B, and return it". So the code creates a movement vector that is your horizontal movement (user input), vertical movement (the vertical movement the rigidbody already has), and then lerp the current velocity to it. By modifying velocity directly, it ensures your movement will stay smooth and constant, so long as you know how to do it right.
If you want a "Physics" based movement then you should apply forces to the Rigidbody. A benefit of acting on the rigidbody is that it will take into account colliding with objects (like walls).
Here is a great intro tutorial (it's 3D but the same concepts apply for 2D). This is the code from that tutorial with some amendments to make it 2D:
using UnityEngine;
using System.Collections;
public class PlayerController : MonoBehaviour {
public float speed; // Here we set a float variable to hold our speed value
private Rigidbody2D rb; // This is to hold the rigidbody component
// Start is called as you start the game, we use it to initially give values to things
void Start ()
{
rb = GetComponent<Rigidbody2D>(); // Here we actually reference the rigidbody.
}
void FixedUpdate ()
{
// We assign values based on our input here:
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
// Here we assign those values to a Vector2 variable.
Vector2 movement = new Vector2 (moveHorizontal, moveVertical);
rb.AddForce (movement * speed); // Finally we apply the forces to the rigidbody
}
}
We can alter the manner in which the force acts on the rigidbody by changing the AddForce.ForceMode2D parameter. For example, ForceMode2D.Force will
Add a force to the rigidbody, using its mass.
ForceMode2D.Impulse will
Add an instant force impulse to the rigidbody2D, using its mass.
which is better for things like jumping.
Note - it is better to put physics-based method calls in FixedUpdate, not in Update, because of frame-rate dependency.
Also note - as you are applying a force to an object, it will accelerate because you are acting on a mass (the rigidbody) and decelerate based on other forces (friction etc.) If you want your player to slow to a halt instead of stop dead, think about the forces acting upon the player. Furthermore, if you apply a force to the rigidbody once per FixedUpdate, this will result in the constant speed you want if you choose ForceMode2D.Forceas other forces acting in the opposite direction will balance it out (see below image - credit to http://www.school-for-champions.com/ for the image).
EDIT: Regarding the comment by rutter above, here is an introductory tutorial on 2D Character controllers.

Categories

Resources