bike movement feels like the bike's on ice when turning - c#

whenever I turn my bike it feels like it's sliding. Here's the script
[SerializeField] float turn;
[SerializeField] float maxSpeed;
[SerializeField] GameObject bikeParts;
[SerializeField] float tilt = 20f;
Rigidbody rb;
float lastY;
void Start()
{
rb = GetComponent<Rigidbody>();
}
void Update()
{
float straightMov = Input.GetAxis("Vertical");
float horizontalMov = Input.GetAxis("Horizontal");
ControlStraightMov(straightMov);
ControlWeightTurning(horizontalMov);
lastY = transform.position.y;
}
private void ControlWeightTurning(float horizontalMov)
{
Vector3 bikePartsRot = bikeParts.transform.eulerAngles;
bikePartsRot.x = tilt * horizontalMov;
bikeParts.transform.eulerAngles = bikePartsRot;
transform.Rotate(0f, (turn * Time.deltaTime) * horizontalMov, 0f);
}
private void ControlStraightMov(float straightMov)
{
if (straightMov > 0)
{
rb.AddRelativeForce((accel * Time.deltaTime) * -straightMov, 0f, 0f);
}
else if (straightMov < 0)
{
rb.AddRelativeForce(((accel / 1.3f * Time.deltaTime) * -straightMov), 0f, 0f);
}
}
Whenever the bike picks up speed, it becomes very difficult to turn the bike because the force that was added keeps moving the bike in a different direction than the direction the bike's facing, how do I apply that force it was facing before on the direction it is facing now so that it doesn't feel like sliding?
I have tried fixing this problem but i just can't because i am pretty new to unity.

how do I apply that force it was facing before on the direction it is facing now
Not sure if this would feel right but you could probably do it like e.g.
private void Update ()
{
...
rb.velocity = transform.forward * rb.velocity.magnitude;
}
Which will keep the current speed and just redirect it into the new forward direction.
In general note: Whenever there is a Rigidbody involved you don't want to set any manipulation through the Transform component but only via the Rigidbody.
So you should not do
bikeParts.transform.eulerAngles = bikePartsRot;
transform.Rotate(0f, (turn * Time.deltaTime) * horizontalMov, 0f);
but both times rather calculate the target rotation and go through e.g. rb.MoveRotation in FixedUpdate.
Which might look somewhat like
float horizontalMove;
void Update()
{
var straightMove = Input.GetAxis("Vertical");
// Get and store the input in Update
horizontalMove = Input.GetAxis("Horizontal");
ControlStraightMov(straightMove);
lastY = transform.position.y;
}
private void FixedUpdate ()
{
// Handle it in FixedUpdate
ControlWeightTurning(horizontalMove);
}
private void ControlWeightTurning(float horizontalMove)
{
var bikePartsRot = bikeParts.transform.eulerAngles;
bikePartsRot.x = tilt * horizontalMove;
// Calculate the new final rotation
var newRotation = Quaternion.Euler(bikePartsRot) * Quaternion.Euler(Vector3.up * (turn * Time.deltaTime) * horizontalMove));
// Apply it only via the Rigidbody
rb.MoveRotation(newRotation);
}

Related

How can I make this unity movement script work?

How can I make this script work, or another alternative player movement script? This basic movement script in Unity doesn't do anything when i press WASD for some reason. I am a beginner at C# and unity and I kind of need an alternative player movement script that actually works.
void Update()
{
if (Input.GetKeyDown(KeyCode.W))
transform.Translate(Vector3.forward);
if (Input.GetKeyDown(KeyCode.S))
transform.Translate(Vector3.back);
if (Input.GetKeyDown(KeyCode.A))
transform.Translate(Vector3.left);
if (Input.GetKeyDown(KeyCode.D))
transform.Translate(Vector3.right);
I recommend using the GetAxis("Horizontal") and GetAxis("Vertical") methods which maps wasd and arrow keys by default to help slim down your big if tree.
Below is a small example from an old unversity project of mine.
Note: the "* speed * Time.deltaTime" as this is used to help translate as time/frames move on, speed is just a multiplier in this case.
public float speed = 10.0f;
private float translation;
private float straffe;
// Use this for initialization
void Start()
{
// turn off the cursor
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void Update()
{
// Input.GetAxis() is used to get the user's input
// You can further set it on Unity. (Edit, Project Settings, Input)
translation = Input.GetAxis("Vertical") * speed * Time.deltaTime;
straffe = Input.GetAxis("Horizontal") * speed * Time.deltaTime;
transform.Translate(straffe, 0, translation);
if (Input.GetKeyDown("escape"))
{
// turn on the cursor
Cursor.lockState = CursorLockMode.None;
}
}
Input.GetKeyDown checks if you pressed the w key on that frame. You need Input.GetKey. That checks if you are holding
You should use GetAxis("Horizontal") & GetAxis("Vertical");
Here is my basic code for my projects default movement:
//movement
Rigidbody rb;
float xInput;
float yInput;
public float speed;
public float defSpeed;
public float sprint;
public bool isGrounded = true;
public float jump;
// Start is called before the first frame update
private void Awake()
{
rb = GetComponent<Rigidbody>();
}
void Start()
{
}
// Update is called once per frame
void Update()
{
xInput = Input.GetAxis("Horizontal");
yInput = Input.GetAxis("Vertical");
//Things is still can't understand
Vector3 input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
float cameraRot = Camera.main.transform.rotation.eulerAngles.y;
rb.position += Quaternion.Euler(0, cameraRot, 0) * input * speed * Time.deltaTime;
//sprint
if (Input.GetKeyDown(KeyCode.LeftShift))
{
speed = sprint;
}
else if (Input.GetKeyUp(KeyCode.LeftShift))
{
speed = defSpeed;
}
//jump
if (Input.GetKeyDown(KeyCode.Space) && isGrounded == true)
{
rb.AddForce(0, jump, 0);
//Debug.Log("Jump!");
}
Hope this helps:)

Rigidbody controlled character moves very strangely when going up slopes

I am making code for a first person physics-based character controller in Unity. The movement is mostly smooth, but when I go up a slope, instead of sliding back down, the character floats in the air slightly while slowly moving downward until it gets back to the ground. This behavior is very strange and unexpected, and I don't really know why this is happening.
The character is an empty object with a capsule and a sphere childed to it. The script is on the empty object, and the rigidbody is on the capsule which is a child to the empty.
Here is the script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
float mouseSensitivity;
private float cameraXRotation;
private float cameraYRotation;
private float movementX;
private float movementY;
private Transform playerHeadTransform;
private Transform playerBodyTransform;
private Rigidbody playerRigidBody;
private bool IsJumping;
// Start is called before the first frame update
void Start()
{
Cursor.lockState = CursorLockMode.Locked;
playerBodyTransform = transform.GetChild(0).gameObject.GetComponent<Transform>();
playerHeadTransform = transform.GetChild(0).transform.GetChild(0).gameObject.GetComponent<Transform>();
playerRigidBody = transform.GetChild(0).gameObject.GetComponent<Rigidbody>();
playerHeadTransform.transform.rotation = Quaternion.Euler(0f, 0f, 0f);
mouseSensitivity = 750;
IsJumping = false;
}
// Update is called once per frame
void Update()
{
#region CameraStuff
float cameraMouseX = Input.GetAxis("Mouse X") * mouseSensitivity * Time.deltaTime;
float cameraMouseY = Input.GetAxis("Mouse Y") * mouseSensitivity * Time.deltaTime;
cameraXRotation -= cameraMouseY;
cameraYRotation += cameraMouseX;
cameraXRotation = Mathf.Clamp(cameraXRotation, -90f, 60);
playerHeadTransform.localRotation = Quaternion.Euler(cameraXRotation, 0f, 0f);
playerBodyTransform.localRotation = Quaternion.Euler(0f, cameraYRotation, 0f);
#endregion
//Movement input variables
movementX = Input.GetAxis("Horizontal") * mouseSensitivity * Time.deltaTime;
movementY = Input.GetAxis("Vertical") * mouseSensitivity * Time.deltaTime;
}
void FixedUpdate()
{
playerRigidBody.velocity = playerBodyTransform.TransformDirection(movementX*2, 0, movementY*2);
}
}
Your player not falling down is most probably related to you setting
void FixedUpdate()
{
playerRigidBody.velocity = playerBodyTransform.TransformDirection(movementX*2, 0, movementY*2);
}
if there is gravity involved you rather want to make sure to not overwrite the Y axis and do e.g.
var currentVelocity = playerRigidbody.velocity;
var newVelocity = playerBodyTransform.TransformDirection(movementX * 2, 0, movementY * 2);
// keep the velocity on Y but only if it is currently downwards
// so you can still move up on a slope but fall down with gravity
if(currentVelocity.y < 0) newVelocity.y = currentVelocity.y;
playerRigidBody.velocity = newVelocity;

Unity 3D movement sliding

I am trying to make a FPS game but when I press w for a bit and then release it slides a bit further than wanted. I am pretty new to Unity and think it has something to do with the updates.
Code:
public float moveSpeed = 5f;
public float jumpForce = 5f;
public CharacterController controller;
private Vector3 moveDirection;
public float gravityScale;
void Start()
{
controller = GetComponent<CharacterController>();
}
void Update()
{
float yStore = moveDirection.y;
moveDirection = (transform.forward * Input.GetAxis("Vertical")) + (transform.right * Input.GetAxis("Horizontal"));
moveDirection = moveDirection.normalized * moveSpeed;
moveDirection.y = yStore;
if (controller.isGrounded)
{
moveDirection.y = 0f;
if (Input.GetButtonDown("Jump"))
{
moveDirection.y = jumpForce;
}
}
moveDirection.y = moveDirection.y + (Physics.gravity.y * gravityScale);
controller.Move(moveDirection * Time.deltaTime);
}
add a physics material to your ground and set the dynamic friction to 1. Next, set the static friction from 0.5 to 1. And last but not least, set the bounciness to 0.
Play around with these values a bit until you find something that is satisfactory.
here is the link to the documentation:
https://docs.unity3d.com/Manual/class-PhysicMaterial.html
it basically explains what each property does.

How to move 2D Object with WASD in Unity

My code below only works for horizontal movement. Shouldn't the vertical movement be working too? I'm just starting out with basic 2D Unity programming:
public class Player : MonoBehaviour {
//These fields will be exposed to Unity so the dev can set the parameters there
[SerializeField] private float speed = 1f;
[SerializeField] private float upY;
[SerializeField] private float downY;
[SerializeField] private float leftX;
[SerializeField] private float rightX;
private Transform _transformY;
private Transform _transformX;
private Vector2 _currentPosY;
private Vector2 _currentPosX;
// Use this for initialization
void Start () {
_transformY = gameObject.GetComponent<Transform> ();
_currentPosY = _transformY.position;
_transformX = gameObject.GetComponent<Transform> ();
_currentPosX = _transformX.position;
}
// Update is called once per frame
void Update () {
_currentPosY = _transformY.position;
_currentPosX = _transformX.position;
float userInputV = Input.GetAxis ("Vertical");
float userInputH = Input.GetAxis ("Horizontal");
if (userInputV < 0)
_currentPosY -= new Vector2 (0, speed);
if (userInputV > 0)
_currentPosY += new Vector2 (0, speed);
if (userInputH < 0)
_currentPosX -= new Vector2 (speed, 0);
if (userInputH > 0)
_currentPosX += new Vector2 (speed, 0);
CheckBoundary ();
_transformY.position = _currentPosY;
_transformX.position = _currentPosX;
}
private void CheckBoundary(){
if (_currentPosY.y < upY)
_currentPosY.y = upY;
if (_currentPosY.y > downY)
_currentPosY.y = downY;
if (_currentPosX.x < leftX)
_currentPosX.x = leftX;
if (_currentPosX.x > rightX)
_currentPosX.x = rightX;
}
}
If I remove/comment out the _currentPosX and it's related codes then my Vertical movement works. But if I remove/comment out the _currentPosY and it's related codes then my Horizontal movement works.
But how come I'm having trouble getting them to work at the same time? I think I'm just missing something but I can't figure it out since I'm just a beginner at this.
Thanks to whoever can give advise.
EDIT: for further clarification...
I'm coding a simple 2d game that will have the player move in 4-directions using the WASD keys.
W = move up
A = move left
S = move down
D = move right
My main problem is that I can get two of the keys working only in one axis: either A and D is working for Horizontal while W and S are not working at all for Vertical movement or vice-versa.
You don't need those if statements. Just use += to append the input to the current transform position.
Move without Rigidbody:
public float speed = 100;
public Transform obj;
public void Update()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
Vector3 tempVect = new Vector3(h, v, 0);
tempVect = tempVect.normalized * speed * Time.deltaTime;
obj.transform.position += tempVect;
}
Move Object with Rigidbody2D:
public float speed = 100;
public Rigidbody2D rb;
public void Update()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
Vector3 tempVect = new Vector3(h, v, 0);
tempVect = tempVect.normalized * speed * Time.deltaTime;
rb.MovePosition(rb.transform.position + tempVect);
}
I suggest using the second code and moving the Rigidbody if you want to be able to detect collison later on.
Note:
You must assign the object to move to the obj slot in the Editor. If using the second code, assign the object with the Rigidbody2D to the rb slot in the Editor.
THIS CODE WORK 100% (you must try it.)
public float moveSpeed = 5;
void Start()
{
}
void Update()
{
if (Input.GetKey(KeyCode.D))
{
transform.position += Vector3.right * moveSpeed * Time.deltaTime;
}
else if (Input.GetKey(KeyCode.A))
{
transform.position += Vector3.right * -moveSpeed * Time.deltaTime;
}
else if (Input.GetKey(KeyCode.W))
{
transform.position += Vector3.up * moveSpeed * Time.deltaTime;
}
else if (Input.GetKey(KeyCode.S))
{
transform.position += Vector3.up * -moveSpeed * Time.deltaTime;
}
}
Try changing the value 0 in the Vector2 functions to current x/ y position...I ran into a similar problem with my project
if (userInputV < 0)
_currentPosY -= new Vector2 (/*current position*/, speed);

How can i make the spaceship to land automatic on the base?

The base is a red cube.
The spaceship is moving already when the game start.
When I click/press the L button the spaceship rotates to face the base and starts moving to it but then when it's getting close to the base it's behaving unexpectedly and the spaceship starts rolling around the base nonstop.
What I want is to make the landing automatic like this youtube video of blender.
I don't want the graphics but the way it's landing.
Blender landing spaceship
And this is a short video clip showing my spaceship when it's start landing:
Landing test
This is the script i'm using for controlling the spaceship and the landing part should be automatic.
The script is attached to the spaceship.
using UnityEngine;
using System.Collections;
public class ControlShip : MonoBehaviour {
public int rotationSpeed = 75;
public int movementspeed = 10;
public int thrust = 10;
public float RotationSpeed = 5;
private bool isPKeyDown = false;
private float acceleration = .0f;
private Vector3 previousPosition = Vector3.zero;
private Rigidbody _rigidbody;
private bool landing = false;
private Vector3 originPosition;
private Vector3 lastPosition;
private const float minDistance = 0.2f;
private Transform baseTarget;
// Use this for initialization
void Start () {
baseTarget = GameObject.Find("Base").transform;
originPosition = transform.position;
_rigidbody = GetComponent<Rigidbody>();
Debug.Log("Acc Speed: " + thrust);
}
// Update is called once per frame
void Update()
{
if (landing == false)
{
var v3 = new Vector3(Input.GetAxis("Vertical"), Input.GetAxis("Horizontal"), 0.0f);
transform.Rotate(v3 * rotationSpeed * Time.deltaTime);
transform.position += transform.forward * Time.deltaTime * movementspeed;
if (Input.GetKey(KeyCode.Z))
transform.Rotate(Vector3.forward * rotationSpeed * Time.deltaTime);
if (Input.GetKey(KeyCode.R))
transform.Rotate(Vector3.right * rotationSpeed * Time.deltaTime);
if (Input.GetKey(KeyCode.P))
{
isPKeyDown = Input.GetKey(KeyCode.P);
float distance = Vector3.Distance(previousPosition, transform.position);
acceleration = distance / Mathf.Pow(Time.deltaTime, 2);
previousPosition = transform.position;
_rigidbody.AddRelativeForce(0f, 0f, thrust, ForceMode.Acceleration);
}
}
else
{
transform.position += transform.forward * Time.deltaTime * movementspeed;
var targetRotation = Quaternion.LookRotation(baseTarget.position - transform.position);
var str = Mathf.Min(.5f * Time.deltaTime, 1);
transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, str);
}
if (landed == true)
TakeOff();
if (Input.GetKey(KeyCode.L))
{
landing = true;
lastPosition = transform.position;
}
}
void OnTriggerEnter(Collider other)
{
if (landing == true && other.gameObject.name == "Base")
{
StartCoroutine(Landed());
}
}
bool landed = false;
IEnumerator Landed()
{
yield return new WaitForSeconds(5);
Debug.Log("Landed");
landed = true;
}
private void TakeOff()
{
if (transform.position != originPosition)
{
_rigidbody.AddForce(transform.up * 10);
}
if ((transform.position - originPosition).sqrMagnitude <= (1f * 1f))
{
landed = false;
_rigidbody.useGravity = false;
}
}
void OnGUI()
{
if (isPKeyDown)
{
GUI.Label(new Rect(100, 100, 200, 200), "Acc Speed: " + acceleration);
}
}
}
This is the part of the landing, should be the part of the landing:
transform.position += transform.forward * Time.deltaTime * movementspeed;
var targetRotation = Quaternion.LookRotation(baseTarget.position - transform.position);
var str = Mathf.Min(.5f * Time.deltaTime, 1);
transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, str);
The spaceship have two components: Rigidbody, Use Gravity set to true. And a Box Collider.
The Base have a box collider component.
You appear to have a box collider on your vehicle and it looks as though it is colliding with the terrain when your code tries to bring it in for a landing. Try switching the collider to be a trigger(tick option on collider component).
Then try it again, as this will not cause physical collisions. If it works or fails for a totally different reason you know this is the cause or a contributing factor.
EDIT: It is worth also noting that when trying to achieve this kind of effect it can be much easier to trigger an animation than try to achieve it in physics based code. Unity offers some great animation controllers and you can call an animation when you need to land since you are taking control away from the player anyway.
While doing this you could turn off the collider so you don't get any strange collision then turn it on when the ship needs to take off, provided you need that of course.
Hope it helps.

Categories

Resources