I have been trying to control the speed of the car in Unity4. I am providing the code details below. Do I need to upgrade the code? As because when the brake(space bar) is pressed the Speed is set to Zero but when the brake is released the Speed is increasing again.
using UnityEngine;
using System.Collections;
public class CarMovementScript : MonoBehaviour
{
public Vector3 com;
public Rigidbody rb;
public WheelCollider FrontLeft;
public WheelCollider FrontRight;
public WheelCollider RearRight;
public WheelCollider RearLeft;
public float maxspeed = 40;
public float carspeed = 0;
public float speed = 0.0f;
float braking = 75.0f;
float turning = 30.0f;
void Start()
{
rb = GetComponent<Rigidbody>();
rb.centerOfMass = new Vector3(rb.centerOfMass.x, -0.9f, rb.centerOfMass.z);
}
void Update()
{
if (speed <= maxspeed)
{
Debug.Log(speed);
//this code makes car go forward
RearRight.motorTorque = Input.GetAxis("Vertical") * speed;
RearLeft.motorTorque = Input.GetAxis("Vertical") * speed;
speed += 0.05f;
}
//this code works for braking of the car
RearRight.brakeTorque = 0;
RearLeft.brakeTorque = 0;
//this code is for turning
FrontRight.steerAngle = Input.GetAxis("Horizontal") * turning;
FrontLeft.steerAngle = Input.GetAxis("Horizontal") * turning;
//Breaking
if (Input.GetKey(KeyCode.Space))
{
RearRight.brakeTorque = braking;
RearLeft.brakeTorque = braking;
speed = 0.0f;
}
}
}
Based on your statement:
when the brake is released the Speed is increasing again.
My guess is that your this piece of code needs attention:
if (speed <= maxspeed)
{
Debug.Log(speed);
//this code makes car go forward
RearRight.motorTorque = Input.GetAxis("Vertical") * speed;
RearLeft.motorTorque = Input.GetAxis("Vertical") * speed;
speed += 0.05f;
}
When you apply break, the speed goes to zero, but since speed <= maxspeed so it returns true and car starts moving due to speed += 0.05f. So you should probably block this condition unless there is an input for vertical axis. Like: (untested, to give you an idea)
float vertical = Input.GetAxis("Vertical");
if ((speed != 0 && speed <= maxspeed) ||
(speed == 0.0 && vertical > 0.0))
{
Debug.Log(speed);
//this code makes car go forward
RearRight.motorTorque = vertical * speed;
RearLeft.motorTorque = vertical * speed;
speed += 0.05f;
}
This way, if condition will execute iff either brake applied and from vertical axis there is a gain in speed or there is already a gain in speed and speed is limited with maxspeed
Hope it helps!
don't set speed to 0 instead decrement it by 0.05f.
remove this
if (speed <= maxspeed)
{
Debug.Log(speed);
//this code makes car go forward
RearRight.motorTorque = Input.GetAxis("Vertical") * speed;
RearLeft.motorTorque = Input.GetAxis("Vertical") * speed;
speed += 0.05f;
}
and change
if (Input.GetKey(KeyCode.Space))
{
RearRight.brakeTorque = braking;
RearLeft.brakeTorque = braking;
speed = 0.0f;
}
to
if (Input.GetKey(KeyCode.Space))
{
RearRight.brakeTorque = braking;
RearLeft.brakeTorque = braking;
speed -= 0.05f;
}
else if (speed <= maxspeed)
{
Debug.Log(speed);
//this code makes car go forward
RearRight.motorTorque = Input.GetAxis("Vertical") * speed;
RearLeft.motorTorque = Input.GetAxis("Vertical") * speed;
speed += 0.05f;
}
This is the code for turning. But the turning gets multiplied automatically at the beginning. What Code changes must be done to adjust the turning?
FrontRight.steerAngle = Input.GetAxis("Horizontal") * turning;
FrontLeft.steerAngle = Input.GetAxis("Horizontal") * turning;
paste this in update function/method.
void Update()
{
//20.0f is maxSpeed
GetComponent<Rigidbody>().velocity = Vector3.ClampMagnitude(GetComponent<Rigidbody>().velocity, 20.0f);
}
Related
I'm working on a 3D fps, and want a dash. The player uses a character controller, and no rigidbody. My original implementation:
x = Input.GetAxis("Horizontal"); //just gets ur wasd inputs by default
z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z; //creates a movement vector
controller.Move(move * speed * Time.deltaTime); //moves the player
if (currentDashLength < dashLength ) //dashes for a set time period
{
currentDashLength += Time.deltaTime;
velocity.y = 0; //keeps you up in the air
controller.Move(move * Time.deltaTime * dashSpeed);
}
else
{
currentDashLength = dashLength;
isDashing = false;
}
if (Input.GetKeyDown(KeyCode.LeftShift) && dashTimer >= 1 && !isCrouching)
{
isDashing = true;
dashTimer -= 1;
currentDashLength = 0f;
health.GiveIFrames(dashLength);
}
This dash works fine, but I realized that if you had pressed shift right after starting to move, the dash would be significantly weaker. I assumed this was due to the fact that my current velocity was low, so the acceleration from the Move function didn't make me reach the speed I would when already moving at terminal velocity. I tried to fix this by multiplying the Move function inputs by 1/(the horizontal velocity of the player) but this didn't fix the issue. My full dashing code:
float dispX = transform.position.x - posX; //gets chnage in position since last frame, this is important to caluclate velocity, since the player isnt using a rigidbody
float dispY = transform.position.y - posY;
float dispZ = transform.position.z - posZ;
posX = transform.position.x;
posY = transform.position.y;
posZ = transform.position.z;
float horizontalVelocity = Mathf.Sqrt(dispX*dispX + dispZ*dispZ) / Time.deltaTime;
x = Input.GetAxis("Horizontal"); //just gets ur wasd inputs by default
z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z; //creates a movement vector
controller.Move(move * speed * Time.deltaTime); //moves the player
if (currentDashLength < dashLength )
{
currentDashLength += Time.deltaTime;
velocity.y = 0;
if(horizontalVelocity == 0)
{
Debug.Log("Cannot dash while standing still");
}
else
{
controller.Move(move * Time.deltaTime * dashSpeed * (1 / horizontalVelocity));
}
}
else
{
currentDashLength = dashLength;
isDashing = false;
}
if (Input.GetKeyDown(KeyCode.LeftShift) && dashTimer >= 1 && !isCrouching)
{
isDashing = true;
dashTimer -= 1;
currentDashLength = 0f;
health.GiveIFrames(dashLength);
}
How would I go about ensuring that the dash speed is constant?
(I tried to post this on unity answers, but the website isn't responding to me)
To get the desired behaviour I have re-written your original script by quite a lot, hope that is okay! This code only give you movement and dash control, and nothing else. You'll have to add your crouch check and health stuff back in.
Essentially, we check if the player is dashing before applying any movement, this way we don't add the dash to the current movement. If the player is dashing, we ignore their forward input and apply forward movement based on the predetermined dash. If we aren't dashing then we apply the calculated movement as usual.
private CharacterController controller;
public float speed = 10.0f;
public float dashSpeed = 20.0f;
public float dashLength = 0.5f;
private float currentDashLength = 0;
private bool isDashing = false;
private void Start()
{
controller = GetComponent<CharacterController>();
}
private void Update()
{
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
// Same as before
Vector3 move = new Vector3(x, 0, z);
// gets the move direction
// before we move, check if dashing
if (isDashing)
{
currentDashLength += Time.deltaTime;
move = new Vector3(move.x * dashSpeed, move.y, 1 * dashSpeed);
// this gets the current player movement, and replaces the forward velocity rather than adding to it. We add to the sideways velocity to allow for slight directional control.
// do this instead if you want the dash to only move the player in the forward direction, and prevent strafing: move = new Vector3(move.x, move.y, 1 * dashSpeed);
if (currentDashLength >= dashLength) // when we run out of time, set dash to false
{
isDashing = false;
}
}
else // if we are not dashing then move as normal
{
move *= speed;
if (Input.GetKeyDown(KeyCode.LeftShift) && move.magnitude > 0) // stops the dash ability being used when stationary
{
isDashing = true;
currentDashLength = 0;
}
}
controller.Move(move * Time.deltaTime);
}
float dispX = transform.position.x - posX;
float dispY = transform.position.y - posY;
float dispZ = transform.position.z - posZ;
posX = transform.position.x;
posY = transform.position.y;
posZ = transform.position.z;
float horizontalVelocity = Mathf.Sqrt(dispX*dispX + dispZ*dispZ) / Time.deltaTime;
x = Input.GetAxis("Horizontal");
z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z;
controller.Move(move * speed * Time.deltaTime);
if (currentDashLength < dashLength )
{
currentDashLength += Time.deltaTime;
velocity.y = 0;
Vector3 dashMove = move * Time.deltaTime * dashSpeed; // Calculates the dash movement vector
// Move the player based on the dash movement vector
controller.Move(dashMove);
}
else
{
currentDashLength = dashLength;
isDashing = false;
}
if (Input.GetKeyDown(KeyCode.LeftShift) && dashTimer >= 1 && !isCrouching)
{
isDashing = true;
dashTimer -= 1;
currentDashLength = 0f;
health.GiveIFrames(dashLength);
}
By calculating the dash movement vector independently from the player's horizontal velocity, you can ensure that the dash speed remains constant regardless of whether the player is moving before dashing or not.
I think this is what you were trying to achieve? Hope it helps!
So, I am still developing a game in Unity, where my only problem now is that I can't figure out how to slowly decrease the speed of my character after releasing left shift. Slowly increasing speed while holding shift is the only one I had worked out because I used the incrementing technique, but the speed slowly decreasing after releasing left shift is not. Can someone help me? Here's the code, I apologize, I am literally a beginner at this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public CharacterController controller;
//Codes for setting walk and sprint speed (You should put speed in "Default Speed". "Walk Speed" is public so I can see if my speed is increasing)
public float defaultSpeed = 8f;
public float walkSpeed = 8f;
public float sprintIncrease = 15f;
public float sprintLimit = 16f;
//Gravity force
public float gravity = -60f;
//Probably jump height?
public float jumpHeight = 2f;
//For checking if you're on the ground
public Transform groundCheck;
public float groundDistance = 0.5f;
public LayerMask groundMask;
//Code to check if you are on the ground
Vector3 velocity;
bool isGrounded;
// Update is called once per frame
void Update()
{
//For checking again if you're on the ground
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
//Code to slowly increase sprint FORWARD while holding left shift
if (Input.GetKey(KeyCode.LeftShift) && Input.GetAxis("Vertical") > 0)
{
walkSpeed += sprintIncrease * Time.deltaTime;
}
//Code to prevent sprinting while holding S and when combined with A or D
else if (Input.GetKey(KeyCode.LeftShift) && Input.GetAxis("Vertical") < 0)
{
walkSpeed = defaultSpeed;
}
//Code for allowing to slowly increase sprint LEFT sideways
else if (Input.GetKey(KeyCode.LeftShift) && Input.GetAxis("Horizontal") < 0)
{
walkSpeed += sprintIncrease * Time.deltaTime;
}
//Code for allowing to slowly increase sprint RIGHT sideways
else if (Input.GetKey(KeyCode.LeftShift) && Input.GetAxis("Horizontal") > 0)
{
walkSpeed += sprintIncrease * Time.deltaTime;
}
//To stop Sprint Speed while holding shift from exceeding Sprint Limit
if (walkSpeed > sprintLimit)
{
walkSpeed = sprintLimit;
}
//Executes when shift is released, to slowly go back to default speed(This is my problem)
if (Input.GetKeyUp(KeyCode.LeftShift))
{
walkSpeed = defaultSpeed;
}
//To check if you're grounded so velocity doesn't increase
if (isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}
//The basic horizontal and vertical axises
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
//The basic code for movement
Vector3 move = transform.right * x + transform.forward * z;
controller.Move(move * walkSpeed * Time.deltaTime);
//The code for jumping
if (Input.GetButtonDown("Jump") && isGrounded)
{
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
}
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
}
}
I thank everyone in advance.
if (!Input.GetKey(KeyCode.LeftShift))
{
walkSpeed -= sprintIncrease * Time.deltaTime;
}
the above code will do what you asked for. Just a heads up, the way you're implementing stuff is beginner-friendly but not performance friendly.
Ok, I have figured this out myself. I rearrange my ifs and else statement to look more organized. I added the else statement where if you don't hold shift while walking, it continuously subtracts the walk speed with the sprint increase, but to stop it from being lower than the default speed, I added an if statement where if the walk speed becomes lower than the default speed, it becomes equal to the default speed. Note that I rearranged my statements to trigger an else statement.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public CharacterController controller;
//Codes for setting walk and sprint speed (You should put speed in "Default Speed". "Walk Speed" is public so I can see if my speed is changing or not)
public float defaultSpeed = 8f;
public float walkSpeed = 8f;
public float sprintIncrease = 15f;
public float sprintLimit = 16f;
//Gravity force
public float gravity = -60f;
//Probably jump height?
public float jumpHeight = 2f;
//For checking if you're on the ground
public Transform groundCheck;
public float groundDistance = 0.5f;
public LayerMask groundMask;
//Code to check if you are on the ground
Vector3 velocity;
bool isGrounded;
// Update is called once per frame
void Update()
{
//For checking again if you're on the ground
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
//Code to prevent sprinting while holding S and when combined with A or D(New Code)
if (Input.GetKey(KeyCode.LeftShift) && Input.GetAxis("Vertical") < 0)
{
walkSpeed -= sprintIncrease * Time.deltaTime;
}
//Code to slowly increase sprint FORWARD while holding left shift
else if (Input.GetKey(KeyCode.LeftShift) && Input.GetAxis("Vertical") > 0)
{
walkSpeed += sprintIncrease * Time.deltaTime;
}
//Code for allowing to slowly increase sprint LEFT sideways
else if (Input.GetKey(KeyCode.LeftShift) && Input.GetAxis("Horizontal") < 0)
{
walkSpeed += sprintIncrease * Time.deltaTime;
}
//Code for allowing to slowly increase sprint RIGHT sideways
else if (Input.GetKey(KeyCode.LeftShift) && Input.GetAxis("Horizontal") > 0)
{
walkSpeed += sprintIncrease * Time.deltaTime;
}
//To make sure that your speed decrease smoothly if not holding left shift(New code)
else
{
walkSpeed -= sprintIncrease * Time.deltaTime;
}
//To stop Sprint Speed while holding shift from exceeding Sprint Limit
if (walkSpeed > sprintLimit)
{
walkSpeed = sprintLimit;
}
//To stop Walk Speed from getting lower than Default Speed(New Code)
if (walkSpeed < defaultSpeed)
{
walkSpeed = defaultSpeed;
}
//To check if you're grounded so velocity doesn't increase
if (isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}
//The basic horizontal and vertical axises
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
//The basic code for movement
Vector3 move = transform.right * x + transform.forward * z;
controller.Move(move * walkSpeed * Time.deltaTime);
//The code for jumping
if (Input.GetButtonDown("Jump") && isGrounded)
{
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
}
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
}
}
If I move forward while looking up my player jumps or at least attempts to fly. If I press Space bar and do move forward while looking up my player jumps even higher. I honestly have no idea on whats's going on. My prediction is the forward. If I look up Forward is relative to where I'm looking.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class P_MOVEMENT : MonoBehaviour
{
private float ACCELERATION = 10.0f;
private float GRAVITY = -5.0f;
private float SPEED = 5.0f;
private float RUNNING_SPEED = 2.0f;
private float JUMP_IMPULSE = 2.5f;
private bool isRunning = false;
CharacterController P_CC;
Vector3 P_MOVE;
//Camera Moving Mouse
private float X_AXIS = 0.0f;
private float Y_AXIS = 0.0f;
private float CAMERA_SPEED = 2.0f;
// Start is called before the first frame update
void Start()
{
P_CC = GetComponent<CharacterController>();
}
// Update is called once per frame
void Update()
{
if(P_CC.isGrounded)
{
// Player Movement
P_MOVE = transform.forward * Input.GetAxis("Vertical") + transform.right * Input.GetAxis("Horizontal");
// Special Cases Check
// Running
isRunning = ( Input.GetKey(KeyCode.LeftShift) ) ? true : false;
P_MOVE = (isRunning) ? P_MOVE * SPEED * RUNNING_SPEED : P_MOVE * SPEED;
// Jumping
if(Input.GetAxis("Jump") > 0)
{
P_MOVE += Vector3.up * JUMP_IMPULSE;
}
}
else
{
P_MOVE += Vector3.up * GRAVITY * Time.deltaTime;
}
// Player Camera Movement
X_AXIS += CAMERA_SPEED * Input.GetAxis("Mouse X");
Y_AXIS -= CAMERA_SPEED * Input.GetAxis("Mouse Y");
// Restrict 90 Degree Up and Down
Y_AXIS = Mathf.Clamp(Y_AXIS, -60f, 90f);
// Update Rotation
transform.eulerAngles = new Vector3(Y_AXIS, X_AXIS, 0.0f);
}
void FixedUpdate()
{
P_CC.Move(P_MOVE * Time.deltaTime);
}
}
You are probably right. Your transform.forward is about the local GameObject coordinates instead of the global ones.
You could try to update only transform.forward.x and transform.forward.z. So you will ignore transform.forward.y. This way the player should not move up.
Something like this:
P_MOVE = transfrom.forward.x * Input.GetAxis("Vertical") + transform.forward.z * Input.GetAxis("Vertical") + transform.right * Input.GetAxis("Horizontal");
Very new to mono develop and Unity 3d and seem to be having issues with this code. First off, the code IS working. It does what it's supposed to, however, it also does some funky stuff that it's not supposed to. You are able to look up, down, left and right as well as walk those directions, the bad part is though for some reason my character likes to nudge the direction of the mouse when standing still. What am I missing? More efficient/less buggy way of doing this?
public class PlayerControl : MonoBehaviour {
public float WALK_SPEED = 1.3f;
public float RUN_SPEED = 4.0f;
public float STRAFE_SPEED = 5.0f;
public float ROTATION_SPEED = 300.0f;
public float JUMP_FORCE = 250.0f;
void Start()
{
}
// Update is called once per frame
void Update ()
{
float movementSpeed = WALK_SPEED;
float strafeSpeed = STRAFE_SPEED;
float rotationSpeedx = ROTATION_SPEED;
float rotationSpeedy = ROTATION_SPEED;
if (Input.GetKey(KeyCode.LeftShift))
{
movementSpeed = RUN_SPEED;
}
movementSpeed = Input.GetAxis("Vertical") * movementSpeed * Time.deltaTime;
strafeSpeed = Input.GetAxis("Horizontal") * strafeSpeed * Time.deltaTime;
rotationSpeedx = Input.GetAxis("Mouse X") * rotationSpeedx * Time.deltaTime;
rotationSpeedy = Input.GetAxis("Mouse Y") * rotationSpeedy * Time.deltaTime;
Vector3 rotate = new Vector3 (-rotationSpeedy, rotationSpeedx, 0);
transform.Translate(Vector3.forward * movementSpeed);
transform.Translate(Vector3.right * strafeSpeed);
transform.Rotate(rotate);
if (Input.GetKeyDown(KeyCode.Space) &&
transform.position.y < 30)
{
rigidbody.AddForce(Vector3.up * JUMP_FORCE);
}
}
}
Try freezing rotation constraints on rigidbody component. This may stop the nudging.
I am trying to build an asteroids style game in Unity and could really use some help. I believe all my math is correct as far as the ship movement but I am having trouble getting it to work inside Unity. I am having a couple different problems.
The ship does not update with velocity ( if you start moving and then let go, it will stand still)
I am unsure in Unity how to set the ships rotation to my specific angle.
Any help would be greatly appreciated.
public class playerController : MonoBehaviour {
public static float timer;
public static bool timeStarted = false;
Vector2 accel;
Vector2 velocity;
float direction;
float angle;
float shotCooldown;
float speed;
const float pi = 3.141592f;
const float maxSpeed = 300;
const float maxAccel = 500;
void Start () {
timeStarted = true;
}
void Update () {
if (timeStarted == true) {
timer += Time.deltaTime;
}
shotCooldown -= (timer%60);
angle = direction * pi / 180;
if (Input.GetKey(KeyCode.W)) {
accel.y = -Mathf.Cos(angle) * maxAccel;
accel.x = Mathf.Sin(angle) * maxAccel;
velocity += accel * Time.deltaTime;
}
if (Input.GetKey(KeyCode.S)) {
accel.y = -Mathf.Cos(angle) * maxAccel;
accel.x = Mathf.Sin(angle) * maxAccel;
velocity -= accel * Time.deltaTime;
}
if (Input.GetKey(KeyCode.Space)) {
if (shotCooldown <= 0)
{
// Create new shot by instantiating a bullet with current position and angle
shotCooldown = .25f;
}
}
if (Input.GetKey(KeyCode.D)) {
direction += 360 * Time.deltaTime;
}
if (Input.GetKey(KeyCode.A)) {
direction -= 360 * Time.deltaTime;
}
/*
if (this.transform.position.x >= Screen.width && velocity.x > 0) {
this.transform.position.x = 0;
}*/
while (direction < 0) {
direction += 360;
}
while (direction > 360) {
direction -= 360;
}
speed = Mathf.Sqrt( (velocity.x * velocity.x) + (velocity.y * velocity.y));
if (speed > maxSpeed) {
Vector2 normalizedVector = velocity;
normalizedVector.x = normalizedVector.x / speed;
normalizedVector.y = normalizedVector.y / speed;
velocity = normalizedVector * maxSpeed;
}
this.transform.position = velocity * Time.deltaTime;
transform.rotation = Quaternion.AngleAxis(0, new Vector3(0,0,angle));
}
}
It's usually a bad idea to set the position the way you are, because you're not actually using any physics. The way you're doing it, velocity is a new position for the ship, not a speed. Once you let go of the keys, it stops calculating new positions, and thus stops moving.
There are a couple of alternatives which would make for a better result:
1) One way this can be done is by calling: transform.Translate(Vector3.forward * speed * Time.deltaTime) Vector3.forward should correspond to the direction you consider as "forward", but if not, you can change it to whichever works (eg Vector3.up). This means you only really need to calculate a speed and let unity hangle the rest.
2) If you're using a rigidbody on your ship, you could simply do:
rigidbody.AddForce(Vector3.forward * speed * Time.deltaTime) which will automatically accelerate the ship in the given direction by whatever speed you give it.
As for rotation, perhaps try something like this:
if (Input.GetKey(KeyCode.D))
{
Vector3 newRotation = transform.rotation.eulerAngles;
newRotation.z += 10;
transform.rotation = Quaternion.Euler (newRotation);
}
else if (Input.GetKey(KeyCode.A))
{
Vector3 newRotation = transform.rotation.eulerAngles;
newRotation.z -= 10;
transform.rotation = Quaternion.Euler (newRotation);
}