unity rigidbody It's going up and bounces when is moving - c#

I have a problem with rigidbody, This is a simple character controller script. the problem is i created some square floor tiles and each floor has mesh collider. soo when the character moving fast on thes floor tiles the charachter will going up a little bit or bounces when moving !! this is a image and a code of script
[]
public class character_controller : MonoBehaviour {
[Header("Speeds")]
public float move_speed;
public float move_smooth;
public float rotate_speed;
[Header("Physics")]
public float gravity_force = -10.0f;
[Header("Distances")]
public float ground_min_dis = 0.25f;
public float ground_max_dis = 100;
[Header("Layers")]
public LayerMask ground_layer;
[HideInInspector] public Rigidbody rb;
[HideInInspector] public Vector3 dir;
[HideInInspector] public Vector3 input;
[HideInInspector] public Vector3 input_smooth;
[HideInInspector] public bool move_to_direction;
[HideInInspector] public bool rotate_to_direction;
[HideInInspector] public bool can_move;
[HideInInspector] public bool is_on_ground;
private float ground_distance;
private RaycastHit ground_hit;
// method: start is called before the first frame update
void Start() {
rb = GetComponent<Rigidbody>();
can_move = true;
move_to_direction = true;
}
// method: update is called once per frame
void Update() {
move_input();
check_ground_distance();
}
// method: fixed update is called every fixed framerate frame
void FixedUpdate() {
if(
move_to_direction
) {
move();
}
}
// method: move input
private void move_input() {
input.x = Input.GetAxis("Vertical");
input.z = Input.GetAxis("Horizontal");
}
// method: move character
private void move() {
// input smooth for moving character smoothly
input_smooth = Vector3.Lerp(input_smooth, input, move_smooth * Time.deltaTime);
// get the forward facing direction of the character
var forward = Vector3.forward;
// get the left facing direction of the character
var right = Vector3.left;
// determine the direction
dir = (input_smooth.x * forward) + (input_smooth.z * right);
// normalize direction
if (
dir.magnitude > 1f
) {
dir.Normalize();
}
Vector3 target_position = rb.position + dir * move_speed * Time.deltaTime;
Vector3 target_velocity = (target_position - transform.position) / Time.deltaTime;
target_velocity.y = rb.velocity.y;
if(
can_move
) {
rb.velocity = target_velocity;
}
if(
input.magnitude > 0.01f
) {
// start rotate to direction
if(
rotate_to_direction == true
) {
start_rotate_to_direction(dir, rotate_speed);
}
}
}
// method: rotate character to direction
public void start_rotate_to_direction(
Vector3 dir,
float speed
) {
Vector3 forward;
Quaternion new_rotation;
forward = Vector3.RotateTowards(transform.forward, dir.normalized, speed * Time.deltaTime, 0.1f);
forward.y = 0;
new_rotation = Quaternion.LookRotation(forward);
transform.rotation = new_rotation;
}
// method: check ground distance
private void check_ground_distance() {
float distance;
Ray ray = new Ray(transform.position, Vector3.down);
// if the ray hit to the ground layer
if (
Physics.Raycast(ray, out ground_hit, ground_max_dis, ground_layer)
) {
if(
!ground_hit.collider.isTrigger
) {
distance = transform.position.y - ground_hit.point.y;
ground_distance = (float)System.Math.Round(distance, 2);
}
}
// check if character on the ground
if(
ground_distance <= ground_min_dis
) {
is_on_ground = true;
} else {
is_on_ground = false;
}
// apply force gravity when falling
if(
is_on_ground == false
) {
rb.AddForce(transform.up * gravity_force * Time.deltaTime, ForceMode.VelocityChange);
}
}}

Can you please read this manual page carefully?
I think, the page explains this phenomena (it is called ghost collision). Probably, your rigidbody hits to the border of mesh colliders just like described in manual.
Also, did you try to freeze motion along related axis by using inspector? It can be a quick solution.

I solved this problem by going into Edit > Project Settings > Physics from Physics tab you can set the Default Contact Offset value from 0.01 to 0.0001.

Related

How to make an FPS Camera using Netcode for gameobjects and FPS Starter Assets?

All I know is that every time a new client joins, all the player set their main camera to that ones.
I use the starter assets but I changed few things to solve this and do the networking:
using Unity.Netcode;
using UnityEngine;
#if ENABLE_INPUT_SYSTEM && STARTER_ASSETS_PACKAGES_CHECKED
using UnityEngine.InputSystem;
#endif
namespace StarterAssets
{
[RequireComponent(typeof(CharacterController))]
#if ENABLE_INPUT_SYSTEM && STARTER_ASSETS_PACKAGES_CHECKED
[RequireComponent(typeof(PlayerInput))]
#endif
public class FirstPersonController : NetworkBehaviour
{
[Header("Player")]
[Tooltip("Move speed of the character in m/s")]
public float MoveSpeed = 4.0f;
[Tooltip("Sprint speed of the character in m/s")]
public float SprintSpeed = 6.0f;
[Tooltip("Rotation speed of the character")]
public float RotationSpeed = 1.0f;
[Tooltip("Acceleration and deceleration")]
public float SpeedChangeRate = 10.0f;
[Space(10)]
[Tooltip("The height the player can jump")]
public float JumpHeight = 1.2f;
[Tooltip("The character uses its own gravity value. The engine default is -9.81f")]
public float Gravity = -15.0f;
[Space(10)]
[Tooltip("Time required to pass before being able to jump again. Set to 0f to instantly jump again")]
public float JumpTimeout = 0.1f;
[Tooltip("Time required to pass before entering the fall state. Useful for walking down stairs")]
public float FallTimeout = 0.15f;
[Header("Player Grounded")]
[Tooltip("If the character is grounded or not. Not part of the CharacterController built in grounded check")]
public bool Grounded = true;
[Tooltip("Useful for rough ground")]
public float GroundedOffset = -0.14f;
[Tooltip("The radius of the grounded check. Should match the radius of the CharacterController")]
public float GroundedRadius = 0.5f;
[Tooltip("What layers the character uses as ground")]
public LayerMask GroundLayers;
[Header("Cinemachine")]
[Tooltip("The follow target set in the Cinemachine Virtual Camera that the camera will follow")]
public GameObject CinemachineCameraTarget;
[Tooltip("How far in degrees can you move the camera up")]
public float TopClamp = 90.0f;
[Tooltip("How far in degrees can you move the camera down")]
public float BottomClamp = -90.0f;
// cinemachine
private float _cinemachineTargetPitch;
// player
private float _speed;
private float _rotationVelocity;
private float _verticalVelocity;
private float _terminalVelocity = 53.0f;
// timeout deltatime
private float _jumpTimeoutDelta;
private float _fallTimeoutDelta;
#if ENABLE_INPUT_SYSTEM && STARTER_ASSETS_PACKAGES_CHECKED
private PlayerInput _playerInput;
#endif
private CharacterController _controller;
private StarterAssetsInputs _input;
[SerializeField] private GameObject _mainCamera;
private const float _threshold = 0.01f;
private bool IsCurrentDeviceMouse
{
get
{
#if ENABLE_INPUT_SYSTEM && STARTER_ASSETS_PACKAGES_CHECKED
return _playerInput.currentControlScheme == "KeyboardMouse";
#else
return false;
#endif
}
}
public override void OnNetworkSpawn()
{
// get a reference to our main camera
if (_mainCamera == null)
{
foreach (Transform child in gameObject.transform)
{
if (child.name == "PlayerCameraRoot")
{
foreach (Transform granchild in child.transform)
{
if (granchild.tag == "MainCamera")
_mainCamera = granchild.gameObject;
}
}
}
}
}
private void Start()
{
if(!IsOwner) return;
_controller = GetComponent<CharacterController>();
_input = GetComponent<StarterAssetsInputs>();
#if ENABLE_INPUT_SYSTEM && STARTER_ASSETS_PACKAGES_CHECKED
_playerInput = GetComponent<PlayerInput>();
#else
Debug.LogError( "Starter Assets package is missing dependencies. Please use Tools/Starter Assets/Reinstall Dependencies to fix it");
#endif
// reset our timeouts on start
_jumpTimeoutDelta = JumpTimeout;
_fallTimeoutDelta = FallTimeout;
Cursor.visible = false;
}
private void Update()
{
if(!IsOwner) return;
JumpAndGravity();
GroundedCheck();
Move();
}
private void LateUpdate()
{
CameraRotation();
}
private void GroundedCheck()
{
// set sphere position, with offset
Vector3 spherePosition = new Vector3(transform.position.x, transform.position.y - GroundedOffset, transform.position.z);
Grounded = Physics.CheckSphere(spherePosition, GroundedRadius, GroundLayers, QueryTriggerInteraction.Ignore);
}
private void CameraRotation()
{
// if there is an input
if (_input.look.sqrMagnitude >= _threshold)
{
//Don't multiply mouse input by Time.deltaTime
float deltaTimeMultiplier = IsCurrentDeviceMouse ? 1.0f : Time.deltaTime;
_cinemachineTargetPitch += _input.look.y * RotationSpeed * deltaTimeMultiplier;
_rotationVelocity = _input.look.x * RotationSpeed * deltaTimeMultiplier;
// clamp our pitch rotation
_cinemachineTargetPitch = ClampAngle(_cinemachineTargetPitch, BottomClamp, TopClamp);
// Update Cinemachine camera target pitch
CinemachineCameraTarget.transform.localRotation = Quaternion.Euler(_cinemachineTargetPitch, 0.0f, 0.0f);
// rotate the player left and right
transform.Rotate(Vector3.up * _rotationVelocity);
}
}
private void Move()
{
// set target speed based on move speed, sprint speed and if sprint is pressed
float targetSpeed = _input.sprint ? SprintSpeed : MoveSpeed;
// a simplistic acceleration and deceleration designed to be easy to remove, replace, or iterate upon
// note: Vector2's == operator uses approximation so is not floating point error prone, and is cheaper than magnitude
// if there is no input, set the target speed to 0
if (_input.move == Vector2.zero) targetSpeed = 0.0f;
// a reference to the players current horizontal velocity
float currentHorizontalSpeed = new Vector3(_controller.velocity.x, 0.0f, _controller.velocity.z).magnitude;
float speedOffset = 0.1f;
float inputMagnitude = _input.analogMovement ? _input.move.magnitude : 1f;
// accelerate or decelerate to target speed
if (currentHorizontalSpeed < targetSpeed - speedOffset || currentHorizontalSpeed > targetSpeed + speedOffset)
{
// creates curved result rather than a linear one giving a more organic speed change
// note T in Lerp is clamped, so we don't need to clamp our speed
_speed = Mathf.Lerp(currentHorizontalSpeed, targetSpeed * inputMagnitude, Time.deltaTime * SpeedChangeRate);
// round speed to 3 decimal places
_speed = Mathf.Round(_speed * 1000f) / 1000f;
}
else
{
_speed = targetSpeed;
}
// normalise input direction
Vector3 inputDirection = new Vector3(_input.move.x, 0.0f, _input.move.y).normalized;
// note: Vector2's != operator uses approximation so is not floating point error prone, and is cheaper than magnitude
// if there is a move input rotate player when the player is moving
if (_input.move != Vector2.zero)
{
// move
inputDirection = transform.right * _input.move.x + transform.forward * _input.move.y;
}
// move the player
_controller.Move(inputDirection.normalized * (_speed * Time.deltaTime) + new Vector3(0.0f, _verticalVelocity, 0.0f) * Time.deltaTime);
}
private void JumpAndGravity()
{
if (Grounded)
{
// reset the fall timeout timer
_fallTimeoutDelta = FallTimeout;
// stop our velocity dropping infinitely when grounded
if (_verticalVelocity < 0.0f)
{
_verticalVelocity = -2f;
}
// Jump
if (_input.jump && _jumpTimeoutDelta <= 0.0f)
{
// the square root of H * -2 * G = how much velocity needed to reach desired height
_verticalVelocity = Mathf.Sqrt(JumpHeight * -2f * Gravity);
}
// jump timeout
if (_jumpTimeoutDelta >= 0.0f)
{
_jumpTimeoutDelta -= Time.deltaTime;
}
}
else
{
// reset the jump timeout timer
_jumpTimeoutDelta = JumpTimeout;
// fall timeout
if (_fallTimeoutDelta >= 0.0f)
{
_fallTimeoutDelta -= Time.deltaTime;
}
// if we are not grounded, do not jump
_input.jump = false;
}
// apply gravity over time if under terminal (multiply by delta time twice to linearly speed up over time)
if (_verticalVelocity < _terminalVelocity)
{
_verticalVelocity += Gravity * Time.deltaTime;
}
}
private static float ClampAngle(float lfAngle, float lfMin, float lfMax)
{
if (lfAngle < -360f) lfAngle += 360f;
if (lfAngle > 360f) lfAngle -= 360f;
return Mathf.Clamp(lfAngle, lfMin, lfMax);
}
private void OnDrawGizmosSelected()
{
Color transparentGreen = new Color(0.0f, 1.0f, 0.0f, 0.35f);
Color transparentRed = new Color(1.0f, 0.0f, 0.0f, 0.35f);
if (Grounded) Gizmos.color = transparentGreen;
else Gizmos.color = transparentRed;
// when selected, draw a gizmo in the position of, and matching radius of, the grounded collider
Gizmos.DrawSphere(new Vector3(transform.position.x, transform.position.y - GroundedOffset, transform.position.z), GroundedRadius);
}
}
}
And this is my Prefab for the player:
enter image description here
My Network Manager:
enter image description here
Note: I don't know if it matters. It probably does not but I am raycasting with the cameras.
I've had some experience with a 2d game but it should also work for 3d fps make a empty gameobject then use that as a parent for the camera then using a new script you can disable it if IsOwner is false (make sure your using Unity.Netcode and instead of a MonoBehaviour you use a NetworkBehaviour otherwise you cant use IsOwner)

Top Down Unity 3d. Player Only Recognizes One Direction as Forward, Left, etc

It says it all in the title, really. I have a blend tree set up with 4 directions and the player moves and rotates perfectly, but if I turn to run directly in (for example) the left direction, the left strafe animation plays while running in that direction. The player is facing in the right direction it is just his legs are playing the wrong animation.
I have tried using "normalized" and "transform.Translate" but nothing seems to make a difference.
public class TwinStickMovement : MonoBehaviour
{
[SerializeField] private float playerSpeed = 5f;
[SerializeField] private float graityValue = -9.81f;
[SerializeField] private float controllerDeadZone = 0.1f;
[SerializeField] private float gamepadRotateSmoothing = 1000f;
[SerializeField] private bool isGamePad;
private CharacterController controller;
private Animator animator;
private Vector2 movement;
private Vector2 aim;
private Vector3 playerVelocity;
private Vector3 lookPoint;
private PlayerControls playerControls;
private PlayerInput playerInput;
private bool animLocked = false;
private void Awake()
{
controller = GetComponent<CharacterController>();
playerControls = new PlayerControls();
playerInput = GetComponent<PlayerInput>();
animator = GetComponent<Animator>();
}
private void FixedUpdate()
{
if (!animLocked && movement != Vector2.zero)
{
animator.SetFloat("moveX", movement.x);
animator.SetFloat("moveY", movement.y);
}
}
private void OnEnable()
{
playerControls.Enable();
}
private void OnDisable()
{
playerControls.Disable();
}
private void Update()
{
HandleInput();
HandleMovement();
HandleRotation();
}
private void HandleInput()
{
movement = playerControls.Controls.Movement.ReadValue<Vector2>();
aim = playerControls.Controls.Aim.ReadValue<Vector2>();
}
private void HandleMovement()
{
Vector3 move = new Vector3(movement.x, 0, movement.y);
controller.Move(move * Time.deltaTime * playerSpeed);
playerVelocity.y += graityValue * Time.deltaTime;
controller.Move(playerVelocity * Time.deltaTime);
}
private void HandleRotation()
{
if (isGamePad)
{
if (Mathf.Abs(aim.x) > controllerDeadZone || Mathf.Abs(aim.y) > controllerDeadZone)
{
Quaternion newrotation = Quaternion.LookRotation(new Vector3(aim.x, 0f, aim.y),Vector3.up);
transform.rotation = Quaternion.RotateTowards(transform.rotation, newrotation, gamepadRotateSmoothing * Time.deltaTime);
}
}
else
{
Ray ray = Camera.main.ScreenPointToRay(aim);
Plane groundPlane = new Plane(Vector3.up, Vector3.zero);
float rayDistance;
if (groundPlane.Raycast(ray, out rayDistance))
{
Vector3 point = ray.GetPoint(rayDistance);
LookAt(point);
}
}
}
private void LookAt(Vector3 point)
{
Vector3 heightCorrectPoint = new Vector3(lookPoint.x, transform.position.y, lookPoint.z);
transform.LookAt(heightCorrectPoint);
}
public void OnDeviceChange(PlayerInput pi)
{
isGamePad = pi.currentControlScheme.Equals("Gamepad") ? true : false;
}
}
I assume that you're using logic that is equivalent to if moveX > 0 and moveY approximatly 0 then play strafe animation. However this doesn't take the players orientation into account and as such only works correctly when you look up. You will need to transform your moveX and moveY into the localspace of lookX and lookY so that the animator can make the appropriate choice.
The left panel shows the information your animator is receiving and based on that it is making the wrong choice and says that your character is strafing. The right panel shows the vector after it was transformed. Here your animator would recognize that you are moving forward stronger than sideways and therefore the strafe is inappropriate and the forward walk animation should play.
I'll abridge the math to make it all work and skip to the interesting bits. Basically you want to transform a uv coordinate system into the xy system. For that you have two given perpendicular vectors (look direction and the "right") in the xy coordinates which you can note in two equations like so:
x = au+bv
y = cu+dv
You can use these to find u and v, which if you do it will be:
u = (by-dx)/(bc-da)
v = (ay-cx)/(cd-ab)
Plugging in all the values and inserting the coordinates that you want to transform into x and y will give you an answer in uv space, which is actually what you need to give to the animator.
Since math is hard and I probably didn't do a particularly good job explaining it, here's the code that does it in Unity:
private Vector2 MovementRelativeToLookdirection(){
float x = movement.x;
float y = movement.y;
float a = transform.forward.x;
float b = transform.forward.z;
float c = transform.right.x;
float d = transform.right.z;
float u = (b*y-d*x)/(b*c-d*a);
float v = (a*y-c*x)/(c*d-a*b);
Vector2 transformedVector = new Vector2(u, v);
return transformedVector;
}
private void FixedUpdate()
{
if (!animLocked && movement != Vector2.zero)
{
Vector2 actualDir = MovementRelativeToLookdirection();
animator.SetFloat("moveX", actualDir.x);
animator.SetFloat("moveY", actualDir.y);
}
}
If my assumption is actually the problem this should fix it.

Unity limit rigidbody velocity in specific direction with addforce?

I am creating a third person player movement script. The movement adds force to the rigidbody relative to the direction of the camera. I want to have a max speed limit in the forward direction (cForward), and a separate max speed limit for the horizontal/right direction (cRight). Normally I would be fine with setting the velocity directly, however this screws up gravity for the player. Is there any way to achieve this by using addforce OR is there a way to get gravity working properly when setting velocity directly? Here is what I have so far(some of my other attempts at a solution are commented out):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public Camera mainCamera;
public float horizontalWalkSpeed = 500.0f;
public float verticalWalkSpeed = 500.0f;
public float horizontalSprintSpeed = 1000.0f;
public float verticalSprintSpeed = 1000.0f;
public bool isSprinting = false;
public bool cannotMove = false;
public float accelerationSpeed = 0.2f;
private Rigidbody pRigidBody;
private Vector2 currentInputVector;
private Vector2 smoothInputVelocity;
// Start is called before the first frame update
void Start()
{
pRigidBody = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
HandleInput();
}
private void FixedUpdate()
{
Vector3 cForward = mainCamera.transform.forward;
Vector3 cRight = mainCamera.transform.right;
cForward.y = 0.0f;
cRight.y = 0.0f;
cForward.Normalize();
cRight.Normalize();
if (!cannotMove && !isSprinting)
{
Vector3 vForce = cForward * currentInputVector.y * verticalWalkSpeed;
Vector3 hForce = cRight * currentInputVector.x * horizontalWalkSpeed;
//Vector3 gravity = Vector3.up * -9.8f;
Vector3 force = vForce + hForce;
//float verSpeed = Vector3.Dot(pRigidBody.velocity, cForward);
//float horSpeed = Vector3.Dot(pRigidBody.velocity, cRight);
//if (verSpeed >= 0 && verSpeed <= verticalWalkSpeed)
//{
// pRigidBody.AddForce(vForce, ForceMode.VelocityChange);
//}
//if(horSpeed < horizontalWalkSpeed)
//{
// pRigidBody.AddForce(hForce, ForceMode.VelocityChange);
//}
//float velocityInDirection = Vector3.Dot(pRigidBody.velocity, cForward);
//if(velocityInDirection > verticalWalkSpeed)
//{
// pRigidBody.AddForce(-vForce, ForceMode.VelocityChange);
//}
//pRigidBody.velocity = force;
pRigidBody.AddForce(force, ForceMode.VelocityChange);
}
else if (!cannotMove && isSprinting)
{
pRigidBody.velocity = cForward * currentInputVector.y * verticalSprintSpeed * Time.fixedDeltaTime + cRight * currentInputVector.x * horizontalSprintSpeed * Time.fixedDeltaTime;
}
}
private void HandleInput()
{
isSprinting = Input.GetButton("Sprint");
Vector2 input = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
currentInputVector = Vector2.SmoothDamp(currentInputVector, input, ref smoothInputVelocity, accelerationSpeed);
}
}
I think this thread may help --https://answers.unity.com/questions/9985/limiting-rigidbody-velocity.html.
Basically, there are two methods.
Add force in the opposite direction and increase with the extent to which the object exceeds the limit. This requires additional calculations and tests.
simply normalize the velocity value when it exceeds the limit.

Why when the camera is child of the character only when pressing on W to move forward the character is not moving and everything is stuttering?

This is the character settings and components :
The character don't move and everything stuttering only when the Camera is child of the character.
If the camera is not child of the character the character will move fine but I want the camera to follow the character.
Maybe I should edit and add the ThirdPersonCharacter script ? It's attached to the character. The script is a bit long.
There are 3 scripts they are all connected a bit long but they are all making the character controlling.
ThirdPersonUserControl :
using System;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
namespace UnityStandardAssets.Characters.ThirdPerson
{
[RequireComponent(typeof (ThirdPersonCharacter))]
public class ThirdPersonUserControl : MonoBehaviour
{
private ThirdPersonCharacter m_Character; // A reference to the ThirdPersonCharacter on the object
private Transform m_Cam; // A reference to the main camera in the scenes transform
private Vector3 m_CamForward; // The current forward direction of the camera
private Vector3 m_Move;
private bool m_Jump; // the world-relative desired move direction, calculated from the camForward and user input.
private void Start()
{
// get the transform of the main camera
if (Camera.main != null)
{
m_Cam = Camera.main.transform;
}
else
{
Debug.LogWarning(
"Warning: no main camera found. Third person character needs a Camera tagged \"MainCamera\", for camera-relative controls.", gameObject);
// we use self-relative controls in this case, which probably isn't what the user wants, but hey, we warned them!
}
// get the third person character ( this should never be null due to require component )
m_Character = GetComponent<ThirdPersonCharacter>();
}
private void Update()
{
if (!m_Jump)
{
m_Jump = CrossPlatformInputManager.GetButtonDown("Jump");
}
}
// Fixed update is called in sync with physics
private void FixedUpdate()
{
// read inputs
float h = CrossPlatformInputManager.GetAxis("Horizontal");
float v = CrossPlatformInputManager.GetAxis("Vertical");
bool crouch = Input.GetKey(KeyCode.C);
// calculate move direction to pass to character
if (m_Cam != null)
{
// calculate camera relative direction to move:
m_CamForward = Vector3.Scale(m_Cam.forward, new Vector3(1, 0, 1)).normalized;
m_Move = v*m_CamForward + h*m_Cam.right;
}
else
{
// we use world-relative directions in the case of no main camera
m_Move = v*Vector3.forward + h*Vector3.right;
}
#if !MOBILE_INPUT
// walk speed multiplier
if (Input.GetKey(KeyCode.LeftShift)) m_Move *= 0.5f;
#endif
// pass all parameters to the character control script
m_Character.Move(m_Move, crouch, m_Jump);
m_Jump = false;
}
}
}
AICharacterControl :
using System;
using UnityEngine;
namespace UnityStandardAssets.Characters.ThirdPerson
{
[RequireComponent(typeof (UnityEngine.AI.NavMeshAgent))]
[RequireComponent(typeof (ThirdPersonCharacter))]
public class AICharacterControl : MonoBehaviour
{
public UnityEngine.AI.NavMeshAgent agent { get; private set; } // the navmesh agent required for the path finding
public ThirdPersonCharacter character { get; private set; } // the character we are controlling
public Transform target; // target to aim for
private void Start()
{
// get the components on the object we need ( should not be null due to require component so no need to check )
agent = GetComponentInChildren<UnityEngine.AI.NavMeshAgent>();
character = GetComponent<ThirdPersonCharacter>();
agent.updateRotation = false;
agent.updatePosition = true;
}
private void Update()
{
if (target != null)
agent.SetDestination(target.position);
if (agent.remainingDistance > agent.stoppingDistance)
character.Move(agent.desiredVelocity, false, false);
else
character.Move(Vector3.zero, false, false);
}
public void SetTarget(Transform target)
{
this.target = target;
}
}
}
ThirdPersonCharacter :
using UnityEngine;
namespace UnityStandardAssets.Characters.ThirdPerson
{
[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(CapsuleCollider))]
[RequireComponent(typeof(Animator))]
public class ThirdPersonCharacter : MonoBehaviour
{
[SerializeField] float m_MovingTurnSpeed = 360;
[SerializeField] float m_StationaryTurnSpeed = 180;
[SerializeField] float m_JumpPower = 12f;
[Range(1f, 4f)][SerializeField] float m_GravityMultiplier = 2f;
[SerializeField] float m_RunCycleLegOffset = 0.2f; //specific to the character in sample assets, will need to be modified to work with others
[SerializeField] float m_MoveSpeedMultiplier = 1f;
[SerializeField] float m_AnimSpeedMultiplier = 1f;
[SerializeField] float m_GroundCheckDistance = 0.1f;
Rigidbody m_Rigidbody;
Animator m_Animator;
bool m_IsGrounded;
float m_OrigGroundCheckDistance;
const float k_Half = 0.5f;
float m_TurnAmount;
float m_ForwardAmount;
Vector3 m_GroundNormal;
float m_CapsuleHeight;
Vector3 m_CapsuleCenter;
CapsuleCollider m_Capsule;
bool m_Crouching;
void Start()
{
m_Animator = GetComponent<Animator>();
m_Rigidbody = GetComponent<Rigidbody>();
m_Capsule = GetComponent<CapsuleCollider>();
m_CapsuleHeight = m_Capsule.height;
m_CapsuleCenter = m_Capsule.center;
m_Rigidbody.constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationY | RigidbodyConstraints.FreezeRotationZ;
m_OrigGroundCheckDistance = m_GroundCheckDistance;
}
public void Move(Vector3 move, bool crouch, bool jump)
{
// convert the world relative moveInput vector into a local-relative
// turn amount and forward amount required to head in the desired
// direction.
if (move.magnitude > 1f) move.Normalize();
move = transform.InverseTransformDirection(move);
CheckGroundStatus();
move = Vector3.ProjectOnPlane(move, m_GroundNormal);
m_TurnAmount = Mathf.Atan2(move.x, move.z);
m_ForwardAmount = move.z;
ApplyExtraTurnRotation();
// control and velocity handling is different when grounded and airborne:
if (m_IsGrounded)
{
HandleGroundedMovement(crouch, jump);
}
else
{
HandleAirborneMovement();
}
ScaleCapsuleForCrouching(crouch);
PreventStandingInLowHeadroom();
// send input and other state parameters to the animator
UpdateAnimator(move);
}
void ScaleCapsuleForCrouching(bool crouch)
{
if (m_IsGrounded && crouch)
{
if (m_Crouching) return;
m_Capsule.height = m_Capsule.height / 2f;
m_Capsule.center = m_Capsule.center / 2f;
m_Crouching = true;
}
else
{
Ray crouchRay = new Ray(m_Rigidbody.position + Vector3.up * m_Capsule.radius * k_Half, Vector3.up);
float crouchRayLength = m_CapsuleHeight - m_Capsule.radius * k_Half;
if (Physics.SphereCast(crouchRay, m_Capsule.radius * k_Half, crouchRayLength, Physics.AllLayers, QueryTriggerInteraction.Ignore))
{
m_Crouching = true;
return;
}
m_Capsule.height = m_CapsuleHeight;
m_Capsule.center = m_CapsuleCenter;
m_Crouching = false;
}
}
void PreventStandingInLowHeadroom()
{
// prevent standing up in crouch-only zones
if (!m_Crouching)
{
Ray crouchRay = new Ray(m_Rigidbody.position + Vector3.up * m_Capsule.radius * k_Half, Vector3.up);
float crouchRayLength = m_CapsuleHeight - m_Capsule.radius * k_Half;
if (Physics.SphereCast(crouchRay, m_Capsule.radius * k_Half, crouchRayLength, Physics.AllLayers, QueryTriggerInteraction.Ignore))
{
m_Crouching = true;
}
}
}
void UpdateAnimator(Vector3 move)
{
// update the animator parameters
m_Animator.SetFloat("Forward", m_ForwardAmount, 0.1f, Time.deltaTime);
m_Animator.SetFloat("Turn", m_TurnAmount, 0.1f, Time.deltaTime);
m_Animator.SetBool("Crouch", m_Crouching);
m_Animator.SetBool("OnGround", m_IsGrounded);
if (!m_IsGrounded)
{
m_Animator.SetFloat("Jump", m_Rigidbody.velocity.y);
}
// calculate which leg is behind, so as to leave that leg trailing in the jump animation
// (This code is reliant on the specific run cycle offset in our animations,
// and assumes one leg passes the other at the normalized clip times of 0.0 and 0.5)
float runCycle =
Mathf.Repeat(
m_Animator.GetCurrentAnimatorStateInfo(0).normalizedTime + m_RunCycleLegOffset, 1);
float jumpLeg = (runCycle < k_Half ? 1 : -1) * m_ForwardAmount;
if (m_IsGrounded)
{
m_Animator.SetFloat("JumpLeg", jumpLeg);
}
// the anim speed multiplier allows the overall speed of walking/running to be tweaked in the inspector,
// which affects the movement speed because of the root motion.
if (m_IsGrounded && move.magnitude > 0)
{
m_Animator.speed = m_AnimSpeedMultiplier;
}
else
{
// don't use that while airborne
m_Animator.speed = 1;
}
}
void HandleAirborneMovement()
{
// apply extra gravity from multiplier:
Vector3 extraGravityForce = (Physics.gravity * m_GravityMultiplier) - Physics.gravity;
m_Rigidbody.AddForce(extraGravityForce);
m_GroundCheckDistance = m_Rigidbody.velocity.y < 0 ? m_OrigGroundCheckDistance : 0.01f;
}
void HandleGroundedMovement(bool crouch, bool jump)
{
// check whether conditions are right to allow a jump:
if (jump && !crouch && m_Animator.GetCurrentAnimatorStateInfo(0).IsName("Grounded"))
{
// jump!
m_Rigidbody.velocity = new Vector3(m_Rigidbody.velocity.x, m_JumpPower, m_Rigidbody.velocity.z);
m_IsGrounded = false;
m_Animator.applyRootMotion = false;
m_GroundCheckDistance = 0.1f;
}
}
void ApplyExtraTurnRotation()
{
// help the character turn faster (this is in addition to root rotation in the animation)
float turnSpeed = Mathf.Lerp(m_StationaryTurnSpeed, m_MovingTurnSpeed, m_ForwardAmount);
transform.Rotate(0, m_TurnAmount * turnSpeed * Time.deltaTime, 0);
}
public void OnAnimatorMove()
{
// we implement this function to override the default root motion.
// this allows us to modify the positional speed before it's applied.
if (m_IsGrounded && Time.deltaTime > 0)
{
Vector3 v = (m_Animator.deltaPosition * m_MoveSpeedMultiplier) / Time.deltaTime;
// we preserve the existing y part of the current velocity.
v.y = m_Rigidbody.velocity.y;
m_Rigidbody.velocity = v;
}
}
void CheckGroundStatus()
{
RaycastHit hitInfo;
#if UNITY_EDITOR
// helper to visualise the ground check ray in the scene view
Debug.DrawLine(transform.position + (Vector3.up * 0.1f), transform.position + (Vector3.up * 0.1f) + (Vector3.down * m_GroundCheckDistance));
#endif
// 0.1f is a small offset to start the ray from inside the character
// it is also good to note that the transform position in the sample assets is at the base of the character
if (Physics.Raycast(transform.position + (Vector3.up * 0.1f), Vector3.down, out hitInfo, m_GroundCheckDistance))
{
m_GroundNormal = hitInfo.normal;
m_IsGrounded = true;
m_Animator.applyRootMotion = true;
}
else
{
m_IsGrounded = false;
m_GroundNormal = Vector3.up;
m_Animator.applyRootMotion = false;
}
}
}
}
In the script ThirdPersonCharacter there is no Update function at all.
In the AICharacterControl there is Update I tried to change it to FixedUpdate but it didn't fix the problem.
In the script ThirdPersonUserControl there is Update but it's only for Jump and there is also FixedUpdate so I didn't try to change anything in that script.
Try using FixedUpdate() instead of Update() and see. Also, you should at least post the relevant bit of code.

Pushes the object on the axes

I have a problem that I can not solve. I have an object, and I want when I click somewhere near him to move with some force. something like the picture below.
I'd even want some idea!!!
Help!!!
public float speed;
public GameObject player;
Vector3 target;
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
var mouseClick = Input.mousePosition;
mouseClick.z = player.transform.position.z - Camera.main.transform.position.z;
target = Camera.main.ScreenToWorldPoint(mouseClick);
var distanceToTarget = Vector3.Distance(player.transform.position, target);
if (distanceToTarget > 2)
{
target.z = 0;
player.GetComponent<Rigidbody2D>().AddForce(target * speed);
}
else
print("travelling COMPLETE");
}
}
Using the code you provided in your answer...
public float speed;
public GameObject player;
Vector3 directionVector;
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
// Input.mousePosition is already in pixel coordinates so the z should already be 0.
Vector3 mouseWorldPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
// Now that the mouse is a world position lets set his z to the same as the player
mouseWorldPosition.z = player.transform.position.z;
// Gives us a direction from the mouse to the player. So think of it as Player <- Mouse remove the < and you have the equation
directionVector = player.transform.position - mouseWorldPosition;
}
else
{
directionVector = Vector3.zero;
}
}
// Physics based movement should be done in FixedUpdate
private void FixedUpdate()
{
player.GetComponent<Rigidbody2D>().AddForce(directionVector.normalized * speed);
}

Categories