Player controller constantly rotates the player when there is no input. The player is idle, not rotating, until the up arrow is pressed. Then it begins rotating constantly.
This happens whether mouseRotate is true or not.
If tried a number of things, including commenting out the mouserotate line altogether, as well as taking out the animations temporarily.
using UnityEngine;
//using UnityStandardAssets.CrossPlatformInput;
using UnityEngine.Networking;
public class PlayerController : MonoBehaviour
{
// Updated 2019-11-06 //
public float movementSpeed=1;
public float runSpeed=2;
bool isOnGround;
Rigidbody rb;
private Vector3 moveDirection = Vector3.zero;
private Animator anim;
public bool mouseRotate = true;
public float rotationSpeed = 200f;
void Start()
{
rb = GetComponent<Rigidbody>();
anim = GetComponent<Animator>();
}
void Update()
{
updateAnim();
ProcessJumping();
moveDirection.y -= 10f * Time.deltaTime;
if (mouseRotate)
{
transform.Rotate(Vector3.up * (Input.GetAxis("Mouse X")) * Mathf.Sign(Input.GetAxis("Horizontal")), Space.World);//mouse rotate
if (Input.GetKey("up") || Input.GetKey("down"))
{
transform.Translate(0, 0, Input.GetAxis("Vertical") * Time.deltaTime * movementSpeed);
}
if (Input.GetKey("left") || Input.GetKey("right"))
{
transform.Translate(Input.GetAxis("Horizontal") * Time.deltaTime * runSpeed, 0, 0);
}
}
else//traditional keyboard controls-- can implement menu to choose rotation style
{
// updated by Yizhi 11/10/2019
if (Input.GetKey("up") || Input.GetKey("down"))
{
transform.Translate(0, 0, Input.GetAxis("Vertical") * Time.deltaTime * movementSpeed);
}
if (Input.GetKey("right") || Input.GetKey("left"))
{
transform.Rotate(0, Input.GetAxis("Horizontal") * Time.deltaTime * rotationSpeed, 0);
}
}
}
void ProcessJumping()
{
CheckIfOnGround();
if (Input.GetKeyDown(KeyCode.Space) && isOnGround)//(Input.GetKeyDown(KeyCode.Space) && isOnGround)//removed until network control implememnted
{
transform.Translate(0, 0.75f, 0);
isOnGround = false;
anim.SetBool("Jump_b", true);
}
}
void CheckIfOnGround() {
Ray[] rays = new Ray[3];
rays[0] = new Ray(transform.position - Vector3.right * .45f, Vector3.down);
rays[1] = new Ray(transform.position, Vector3.down);
rays[2] = new Ray(transform.position + Vector3.right * .45f, Vector3.down);
RaycastHit hit;
float maxD = .1f;
foreach (Ray ray in rays)
{
if (Physics.Raycast(ray, out hit, maxD))
{
if (hit.collider != null)
{
isOnGround = true;
}
else
{
isOnGround = false;
}
}
}
}
void updateAnim()
{
if ( (Input.GetKey(KeyCode.UpArrow) && Input.GetKey(KeyCode.RightShift)))//(Input.GetKey(KeyCode.UpArrow) && Input.GetKey(KeyCode.LeftShift) ||//temporarily removed until network controls are added. Left keyboard belongs to julie, right keyboard belongs to dot
{
// Updated 2019-11-06 //
anim.SetFloat("Speed_f", runSpeed);
}
else if (Input.GetKey(KeyCode.UpArrow) || Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.LeftArrow) || Input.GetKey(KeyCode.DownArrow))
{
// Updated 2019-11-06 //
anim.SetFloat("Speed_f", movementSpeed);
}
else
{
//ELSE idle
anim.SetFloat("Speed_f", 0);
}
}
}
You setup your rigidbody to not rotate your object by locking those rotational axis on the rigidbody component, then if you do need to rotate your player you can manually do it through code. This has been the approach I have successfully used in the past. :)
Related
I'm making a game with firstperson camera. Now I want the player to look at items during cutscenes. This works. the only problem is when the cutscene is over the camera shoots back to the old position so it looks weird. I tried locking and unlocking the cursor so it's in the center but this does nothing. Any ideas?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
using Cursor = UnityEngine.Cursor;
public class PlayerLook : MonoBehaviour
{
public float mouseSensitivity = 100f;
public Transform playerBody;
public bool mayLook;
private bool _lookAtTarget;
private float xRotation = 0;
private Transform _target;
// Start is called before the first frame update
private void Start()
{
mayLook = true;
}
// Update is called once per frame
void Update()
{
if (mayLook)
{
HandleLook();
}
if (_lookAtTarget)
{
Quaternion targetRotation = Quaternion.LookRotation(_target.position - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, 5f * Time.deltaTime);
}
}
void HandleLook()
{
if (mayLook)
{
float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * Time.deltaTime;
float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity * Time.deltaTime;
xRotation -= mouseY;
xRotation = Mathf.Clamp(xRotation, -90f, 90f);
transform.localRotation = Quaternion.Euler(xRotation, 0f, 0f);
playerBody.Rotate(Vector3.up * mouseX);
}
}
public void lookTowards(Transform target)
{
_target = target;
_lookAtTarget = true;
}
public void resetCamera()
{
_lookAtTarget = false;
Cursor.lockState = CursorLockMode.Locked;
Cursor.lockState = CursorLockMode.None;
mayLook = true;
}
}
You can try to save the camera's rotation before the cutscene starts and then restore it after the cutscene is over. Add a Quaternion variable to store the camera's rotation, then use it to set the camera's rotation in your resetCamera method.
It could go like so:
public class PlayerLook : MonoBehaviour
{
// ...
private Quaternion savedRotation;
// Start is called before the first frame update
private void Start()
{
mayLook = true;
// Save the initial camera rotation
savedRotation = transform.rotation;
}
// ...
public void lookTowards(Transform target)
{
_target = target;
_lookAtTarget = true;
}
public void resetCamera()
{
_lookAtTarget = false;
// Restore the saved camera rotation
transform.rotation = savedRotation;
Cursor.lockState = CursorLockMode.Locked;
Cursor.lockState = CursorLockMode.None;
mayLook = true;
}
}
I am working on a project where a player can control a cube and move it around. I love having physics on the cube, but when manuevering, it is very difficult to time a jump when the cube is spinning all over the place. I would like the player to be able to move the cube along the ground, and the cube would gradually tilt towards the direction they are moving it, but not flip entirely. I don't know if it would even work conceptually, but if someone could help me figure out how to alter my code to keep it grounded but still tilt. Thank you.
{
public GameObject Camera;
Collider coll;
private bool isGrounded;
Rigidbody rb;
Vector3 velocity;
public float speed = 12f;
public float gravity = -9.8f;
public float jumpStrength = 1000f;
// Start is called before the first frame update
void Start()
{
Camera = GameObject.Find("Main Camera");
rb = GetComponent<Rigidbody>();
}
void OnCollisionEnter(UnityEngine.Collision collision)
{
if (collision.gameObject.tag == "Floor")
{
isGrounded = true;
Debug.Log("Is Grounded");
}
}
void OnCollisionExit(UnityEngine.Collision collision)
{
if (collision.gameObject.tag == "Floor")
{
isGrounded = false;
Debug.Log("Is Not Grounded");
}
}
// Update is called once per frame
void Update()
{
Camera.transform.position = new Vector3(transform.position.x, transform.position.y + 2.38f, transform.position.z - 3.45f);
if (isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}
float mH = Input.GetAxis("Horizontal");
float mV = Input.GetAxis("Vertical");
rb.velocity = new Vector3(mH * speed, rb.velocity.y, mV * speed);
if(isGrounded && Input.GetButtonDown("Jump"))
{
velocity.y = Mathf.Sqrt(3 * -2 * gravity);
}
velocity.y += gravity * Time.deltaTime;
if(Input.GetButtonDown("Jump") && isGrounded)
{
rb.AddForce(0f, jumpStrength, 0f);
Debug.Log("Jump");
}
}
}
I'm using Photon for multiplayer unity game. You can shoot balls by clicking space and move using wsad. When the ball hits the player it knocks the player back. I'm not adding any extra force when the ball hits the player. Its the default physics. The problem is, whenever player1 gets hit by a ball by player2, player1 position lags and isn't synching properly.
This is the demo: https://humbledev.itch.io/fight-me
Player prefab has a photon view, photon transform view classic and photon rigidbody view components to it.
PlayerController
private void Start()
{
rb = GetComponent<Rigidbody>();
rb.freezeRotation = true;
anim = GetComponent<Animator>();
trail = GetComponent<TrailRenderer>();
view = GetComponent<PhotonView>();
}
private void Update()
{
if(view.IsMine){
horizontalInput = Input.GetAxisRaw("Horizontal");
verticalInput = Input.GetAxisRaw("Vertical");
IsJumping = Input.GetKeyDown(KeyCode.Space);
IsShooting = Input.GetMouseButtonDown(0);
IsGrounded = Physics.CheckSphere(groundCheck.position, groundRadius, groundMask);
if(IsJumping && IsGrounded){
rb.AddForce(Vector3.up * jump, ForceMode.Impulse);
}
if(!IsGrounded){
trail.emitting = true;
}else{
trail.emitting = false;
}
if(IsShooting){
view.RPC("RPC_Shoot", RpcTarget.All);
}
}
}
private void FixedUpdate() {
movement = new Vector3(horizontalInput, 0, verticalInput).normalized;
if(movement != Vector3.zero){
anim.SetBool("IsRunning", true);
Quaternion targetRotation = Quaternion.LookRotation(movement);
targetRotation = Quaternion.RotateTowards(transform.rotation, targetRotation, rotationSpeed * Time.fixedDeltaTime);
rb.MovePosition(rb.position + movement * speed * Time.fixedDeltaTime);
rb.MoveRotation(targetRotation);
}else{
anim.SetBool("IsRunning", false);
}
if(IsJumping && IsGrounded){
// rb.AddForce(Vector3.up * jump, ForceMode.Impulse);
}
if(rb.velocity.y < 0){
rb.velocity += Vector3.up * Physics.gravity.y * (fallMultiplier - 1) * Time.deltaTime;
}else if(rb.velocity.y > 0 && !IsJumping){
rb.velocity += Vector3.up * Physics.gravity.y * (lowMultiplier - 1) * Time.deltaTime;
}
}
[PunRPC]
void RPC_Shoot(){
GameObject bullet = Instantiate(bulletPrefab, aim.transform.position, Quaternion.identity);
bullet.GetComponent<Rigidbody>().velocity = aim.transform.forward * bulletSpeed;
}
private void OnCollisionEnter(Collision other) {
if(other.gameObject.tag == "Bullet"){
view.RPC("RPC_Hit", RpcTarget.All, other.gameObject);
}
}
[PunRPC]
void RPC_Hit(GameObject item){
Destroy(item);
}
Sadly you cannot have a rigidbody that uses gravity sync the transform, you would have to make the rigidbody kinematic and use gravity off. Something Like this:
public Rigidbody[] PlayerOwnedRigidbody;
if (photonView.IsMine) return;
foreach (var item in PlayerOwnedRigidbody)
{
item.isKinematic = true;
item.useGravity = false;
}
I'm creating a Mario clone and I need to keep the player's forward momentum into the jump and then onward into the landing. I can't figure out how to achieve this. Every time I land, the player has to build up momentum again. Any Idea how to fix this? I've tried several solutions to no avail. I'm thinking it has something to do with how I'm adding force and acceleration to the player when holding left or right. Not sure though any help would be much appreciated. thanks in advance.
Here's my code:
Animator animator;
Rigidbody2D rb;
bool isGrounded;
public float moveSpeed;
public Vector2 acceleration;
public float jumpHeight;
public float lowjumpMultiplier;
public Transform groundCheckM;
public Transform groundCheckL;
public Transform groundCheckR;
public float storedValue;
void Start()
{
animator = GetComponent<Animator>();
rb = GetComponent<Rigidbody2D>();
transform.eulerAngles = new Vector3(0, 0, 0);
}
private void Update()
{
if
((Physics2D.Linecast(transform.position,groundCheckM.position, 1 << LayerMask.NameToLayer("Floor/Platforms"))) || //Check if grounded
(Physics2D.Linecast(transform.position, groundCheckL.position, 1 << LayerMask.NameToLayer("Floor/Platforms"))) ||
(Physics2D.Linecast(transform.position, groundCheckR.position, 1 << LayerMask.NameToLayer("Floor/Platforms"))))
{
isGrounded = true;
animator.SetBool("Jump", false);
}
else
{
isGrounded = false;
}
animator.SetFloat("Walk", rb.velocity.x); //Set animation float to x velocity
if (rb.velocity.x <= 0.03f && rb.velocity.x >= -0.03f && isGrounded) //Play "Idle" animation
{
animator.Play("Mario_Idle");
}
if (rb.velocity.x >=4 || rb.velocity.x <=-4)
{
animator.speed = Mathf.Abs(rb.velocity.x / 5.5f); //Increase speed of walking animation with player's walking speed
}
}
void FixedUpdate()
{
if (Input.GetKey("d") || Input.GetKey("right")) //Move player to the right
{
rb.AddForce(acceleration * rb.mass);
transform.rotation = Quaternion.Euler (0, 0, 0);
}
else if (Input.GetKey("a") || Input.GetKey("left")) //Move player to the left
{
rb.AddForce(-acceleration * rb.mass);
transform.rotation = Quaternion.Euler(0, 180, 0);
}
if (rb.velocity.x >= 10)
{
rb.velocity = new Vector2(10, rb.velocity.y); //Cap player speed at 10 when moving right
}
else if (rb.velocity.x <= -10)
{
rb.velocity = new Vector2(-10, rb.velocity.y); //Cap player speed at 10 when moving left
}
if (Input.GetKey("space") && isGrounded) //Player jump
{
rb.velocity += new Vector2(rb.velocity.x, jumpHeight);
animator.SetBool("Jump", true);
}
}
}
I feel dumb but the answer was in the physics material. Once I lowered the friction, it allowed momentum from the jump to carry into the player's run speed. I guess it's a good reminder to tinker directly inside Unity and its built in physics system.
If you want to keep your momentum when jumping, you could store it in a variable that will increase until it reaches the max, or you let go of the key.
float acceleration;
float accelFactor = 0.6f;
float deAccelFactor = 1f;
bool jumping; //you should set it to true when jumping and false, when not.
Rigidbody2D rb;
void Start(){
rb = GetComponent<Rigidbody2D>();
}
void Update(){
if (Input.GetKeyDown(KeyCode.D))
{
Accelerate();
rb.AddForce(acceleration * rb.Mass);
}
else if (jumping)
{
rb.AddForce(acceleration * rb.Mass);
}
else
{
DeAccel();
}
}
void Accelerate(){
acceleration += accelFactor * Time.deltaTime;
acceleration = Mathf.Clamp(acceleration, 0, maxAccel);
}
void DeAccel(){
acceleration -= deAccelFactor * Time.deltaTime;
acceleration = Mathf.Clamp(acceleration, 0, maxAccel);
}
This is what I would recommend using, that is, if I understand what you mean.
I am working on unity ball game. My player is a ball and it uses a player control script. When the ball jumps in air, it can still be controlled and mo move to any direction while its in air. I do not want that as it fails the purpose of heaving a maze since it can fly above obstacles.
I am using a player control script that came with a free unity game kit. I have tried to fix it, but I am only capable of either removing the jump function or reducing its height, and could not fix the issue.
using UnityEngine;
using System.Collections;
public class PlayerControl : MonoBehaviour
{
private GameObject moveJoy;
private GameObject _GameManager;
public Vector3 movement;
public float moveSpeed = 6.0f;
public float jumpSpeed = 5.0f;
public float drag = 2;
private bool canJump = true;
void Start()
{
moveJoy = GameObject.Find("LeftJoystick");
_GameManager = GameObject.Find("_GameManager");
}
void Update ()
{
Vector3 forward = Camera.main.transform.TransformDirection(Vector3.forward);
forward.y = 0;
forward = forward.normalized;
Vector3 forwardForce = new Vector3();
if (Application.platform == RuntimePlatform.Android)
{
float tmpSpeed = moveJoy.GetComponent<Joystick>().position.y;
forwardForce = forward * tmpSpeed * 1f * moveSpeed;
}
else
{
forwardForce = forward * Input.GetAxis("Vertical") * moveSpeed;
}
rigidbody.AddForce(forwardForce);
Vector3 right= Camera.main.transform.TransformDirection(Vector3.right);
right.y = 0;
right = right.normalized;
Vector3 rightForce = new Vector3();
if (Application.platform == RuntimePlatform.Android)
{
float tmpSpeed = moveJoy.GetComponent<Joystick>().position.x;
rightForce = right * tmpSpeed * 0.8f * moveSpeed;
}
else
{
rightForce= right * Input.GetAxis("Horizontal") * moveSpeed;
}
rigidbody.AddForce(rightForce);
if (canJump && Input.GetKeyDown(KeyCode.Space))
{
rigidbody.AddForce(Vector3.up * jumpSpeed * 100);
canJump = false;
_GameManager.GetComponent<GameManager>().BallJump();
}
}
void OnTriggerEnter(Collider other)
{
if (other.tag == "Destroy")
{
_GameManager.GetComponent<GameManager>().Death();
Destroy(gameObject);
}
else if (other.tag == "Coin")
{
Destroy(other.gameObject);
_GameManager.GetComponent<GameManager>().FoundCoin();
}
else if (other.tag == "SpeedBooster")
{
movement = new Vector3(0,0,0);
_GameManager.GetComponent<GameManager>().SpeedBooster();
}
else if (other.tag == "JumpBooster")
{
movement = new Vector3(0,0,0);
_GameManager.GetComponent<GameManager>().JumpBooster();
}
else if (other.tag == "Teleporter")
{
movement = new Vector3(0,0,0);
_GameManager.GetComponent<GameManager>().Teleporter();
}
}
void OnCollisionEnter(Collision collision)
{
if (!canJump)
{
canJump = true;
_GameManager.GetComponent<GameManager>().BallHitGround();
}
}
void OnGUI()
{
GUI.Label(new Rect(300,10,100,100),"X: " + moveJoy.GetComponent<Joystick>().position.x.ToString());
GUI.Label(new Rect(300,30,100,100),"Y: " + moveJoy.GetComponent<Joystick>().position.y.ToString());
}
}
The question has been answered. Now how to use this script -> Create a sphere and give it "Sphere Collider", "Mesh Renderer", "Rigidbody", "Player Control(Script)" Under player control script put this script and your done. Now you have a ball that can be controlled in ios,android and pc i guess and can jump.
I think canJump flag says "Player on the ground". So, if you "can't jump", that means you shouldn't allow gamer to control the character as it is flying. Check it in very start of Update() and call return; if canJump == false