How to keep Horizontal Movement Value thru time in c# Unity? - c#

So I am making game and I need good PlayerMovement Script but there is little problem. You see I made so that my player is following this path (I didn't make it I downloaded it from marketplace) and he can go only forward. Then I put another Vector3 (horizontalMove) value and hooked it to transform.position and didn't get what I really wanted. When I hit play everything works and I can go Left to Right but my position does not stay the same. The moment I let go of my keys (a, d) my player returns to track, resets in middle. I need it to stay in the position I left him. And too, just adding rb.position in my transform.position just send me flying in the air. I need help.
`public class PathFollower : MonoBehaviour
{
public PathCreator pathCreator;
public EndOfPathInstruction endOfPathInstruction;
public float speed = 5;
float distanceTravelled;
float horizontalInput;
[SerializeField] float horizontalMultiplier = 2;
public Rigidbody rb;
void Start() {
if (pathCreator != null)
{
// Subscribed to the pathUpdated event so that we're notified if the path changes during the game
pathCreator.pathUpdated += OnPathChanged;
}
}
void Update()
{
if (pathCreator != null)
{
horizontalInput = Input.GetAxis("Horizontal");
Vector3 horizontalMove = transform.right * horizontalInput * speed * Time.fixedDeltaTime * horizontalMultiplier;
distanceTravelled += speed * Time.deltaTime;
Debug.Log();
transform.position = pathCreator.path.GetPointAtDistance(distanceTravelled, endOfPathInstruction) + new Vector3 (0,1,0) + horizontalMove;
transform.rotation = pathCreator.path.GetRotationAtDistance(distanceTravelled, endOfPathInstruction);
}
}
// If the path changes during the game, update the distance travelled so that the follower's position on the new path
// is as close as possible to its position on the old path
void OnPathChanged() {
distanceTravelled = pathCreator.path.GetClosestDistanceAlongPath(transform.position);
}
}
}`

You need a global variable that holds the value of horizontalMove, so it isn't reset in the update loop.
Vector3 horizontalMove;
void Update()
{
if (pathCreator != null)
{
horizontalInput = Input.GetAxis("Horizontal");
Vector3 horizontalMove += transform.right * horizontalInput * speed * Time.deltaTime * horizontalMultiplier;
distanceTravelled += speed * Time.deltaTime;
Debug.Log();
transform.position = pathCreator.path.GetPointAtDistance(distanceTravelled, endOfPathInstruction) + new Vector3 (0,1,0) + horizontalMove;
transform.rotation = pathCreator.path.GetRotationAtDistance(distanceTravelled, endOfPathInstruction);
}
}
I also took the liberty to change fixedDeltaTime to deltaTime, since that is the appropriate variable for an Update context.

Related

Unity - WASD Movement in Unity 3D

Hello again my friends.
I am trying to make a 3D game in Unity in which I am trying to move my character with simple WASD keys.
However, it is successful only from one direction. From the opposite direction the controls seem reversed. Even when I look around with the mouse. The game is considered to be a First-Person Shooter(FPS).
The Player code is:
[SerializeField]
private NavMeshAgent navMeshAgent;
// Start is called before the first frame update
void Start()
{
controller = GetComponent<CharacterController>();
}
// Update is called once per frame
void Update()
{
Vector3 direction = new Vector3(Input.GetAxis("Horizontal1"), 0, Input.GetAxis("Vertical1"));
Vector3 velocity = direction * speed;
velocity.y -= gravity;
velocity = transform.TransformDirection(velocity);
controller.Move(direction * Time.deltaTime);
transform.position = navMeshAgent.nextPosition;
}
What should I do? I would really appreciate your help.
Try this example to move your character use your own logic ofc and change what have to be changed
private float speed = 2.0f;
public GameObject character;
void Update () {
if (Input.GetKeyDown(d)){
transform.position += Vector3.right * speed * Time.deltaTime;
}
if (Input.GetKeyDown(a)){
transform.position += Vector3.left* speed * Time.deltaTime;
}
if (Input.GetKeyDown(w)){
transform.position += Vector3.forward * speed * Time.deltaTime;
}
if (Input.GetKeyDown(s)){
transform.position += Vector3.back* speed * Time.deltaTime;
}
}

Correct way to rotate object after instancing it in unity

So I'm making a top down shooting game and I want the bullets to align with the direction they are shot at.
I'm passing the direction when instancing the bullet(code bellow) and applying it on the Start event but it doesn't rotate. However it applies when i use it on the Update event indicating that the value is indeed passed but somehow the Start event isn't able to rotate the object. I also tried the OnEnable event and same thing, it seems inneficient to set the rotation in every Update event how can i fix it.
{
[SerializeField] private float speed = 1f;
public Vector3 direction = Vector3.forward;
private float distanceTravelled = 0f;
void Start()
{
transform.LookAt(direction);;
}
void Update()
{
transform.position += speed * Time.deltaTime * direction;
distanceTravelled += speed * Time.deltaTime;
if (distanceTravelled > range)
{
Destroy(gameObject);
}
}
}
I think i fixed it, if theres a better solution please tell me :)
I used Invoke fujnction, it seems to delay the rotation enough so it gets properly applied.
{
[SerializeField] private float speed = 1f;
public Vector3 direction = Vector3.forward;
private float distanceTravelled = 0f;
void Start()
{
Invoke(nameof(SetForwardVector), 0f);
}
void Update()
{
transform.position += speed * Time.deltaTime * direction;
distanceTravelled += speed * Time.deltaTime;
if (distanceTravelled > range)
{
Destroy(gameObject);
}
}
void SetForwardVector()
{
transform.LookAt(direction);
}
}

Why is my character's horizontal velocity lost when jumping?

GOAL
I'm relatively new to Unity and I want my character to be able to run and jump at the same time causing the character to go up diagonally.
PROBLEM
However after making some adjustments to give the character some acceleration, the jump seems to clear all existing velocity, meaning the character goes up and then to the side instead of both at the same time:
(I apologise if its a bit hard to see)
CODE
This is my character movement script:
Rigidbody2D rb;
BoxCollider2D bc;
[Header("Run")]
float xInput = 0f;
public float maxRunSpeed;
public float acceleration;
[Space]
[Header("Jump")]
public float jumpHeight;
public float lowJumpHeight;
public float fallSpeed;
public float airControl;
[Space]
public LayerMask groundLayer;
public bool onGround;
[Space]
public Vector2 bottomOffset;
public Vector2 boxSize;
public float coyoteTime;
void Start() {
// Gets a reference to the components attatched to the player
rb = GetComponent<Rigidbody2D>();
bc = GetComponent<BoxCollider2D>();
}
void Update() {
Jump();
// Takes input for running and returns a value from 1 (right) to -1 (left)
xInput = Math.Sign(Input.GetAxisRaw("Horizontal"));
}
// Applies a velocity scaled by runSpeed to the player depending on the direction of the input
// Increaces the velocity by accerleration until the max velocity is reached
void FixedUpdate() {
rb.velocity = Math.Abs(rb.velocity.x) < Math.Abs(xInput) * maxRunSpeed ? rb.velocity + new Vector2(acceleration * xInput, rb.velocity.y) * Time.deltaTime : new Vector2(xInput * maxRunSpeed, rb.velocity.y);
}
void Jump() {
// Checks whether the player is on the ground and if it is, replenishes coyote time, but if not, it starts to tick it down
coyoteTime = onGround ? 0.1f : coyoteTime - Time.deltaTime;
// Draws a box to check whether the player is touching objects on the ground layer
onGround = Physics2D.OverlapBox((Vector2)transform.position + bottomOffset, boxSize, 0f, groundLayer);
// Adds an upwards velocity to player when there is still valid coyote time and the jump button is pressed
if (Input.GetButtonDown("Jump") && coyoteTime > 0) {
rb.velocity = Vector2.up * jumpHeight;
}
// Increases gravity of player when falling down or when the jump button is let go mid-jump
if (rb.velocity.y < 0 ) {
rb.velocity += Vector2.up * Physics2D.gravity.y * (fallSpeed - 1) * Time.deltaTime;
} else if (rb.velocity.y > 0 && !Input.GetButton("Jump")) {
rb.velocity += Vector2.up * Physics2D.gravity.y * (lowJumpHeight - 1) * Time.deltaTime;
}
}
Sorry for there being a lot of unecessary code, it's just im not sure what's causing the issue so i don't want to remove anything. Hopefully my comments make some sense?
This is happening because you're setting the velocity of your rigidbody directly with rb.velocity = Vector2.up * jumpHeight. So that will wipe all existing velocity.
If you want to just add a force to the velocity rather than replacing it entirely, you can do that with methods like Rigidbody2D.AddForce.
While in all other cases you keep your velocity values and only slightly modify them you are hard overwriting the absolute velocity in
rb.velocity = Vector2.up * jumpHeight;
erasing any velocity on X.
You could simply keep whatever you have on the other axis and only overwrite Y like
var velocity = rb.velocity;
velocity.y = jumpHeight;
rb.velocity = velocity;
or
rb.velocity = new Vector2(rb.velocity.x, jumpHeight);
basically the same way you do it also in FixedUpdate for the horizontal direction.

bike movement feels like the bike's on ice when turning

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);
}

Unity converting Character Controller code to Rigidbody code

I got a movement relative to the camera. Like Super Mario 64 etc. First i made it with a CharacterController but I want to have the default collision detection so I need to use a collider with a Rigidbody.
My code looks this:
public class PlayerMovementController : PlayerCommonController
{
PlayerMovementData data; // data class
PlayerMovementView view; // animation, etc. ... class
float turnSmoothVelocity;
float speedSmoothVelocity;
private void Start()
{
data = new PlayerMovementData();
view = new PlayerMovementView();
}
private void Update()
{
Vector2 inputDirection = (new Vector2(data.InputHorizontal, data.InputVertical)).normalized; // get the inputs
if (Input.GetButtonDown("Jump"))
{
if (data.PlayerCharacterController.isGrounded) // player is on ground?
data.VelocityY = Mathf.Sqrt(-2 * data.PlayerGravity * data.JumpPower);
}
if (inputDirection != Vector2.zero) // Rotate the player
{
transform.eulerAngles = Vector3.up * Mathf.SmoothDampAngle(
transform.eulerAngles.y,
Mathf.Atan2(inputDirection.x, inputDirection.y) * Mathf.Rad2Deg + data.CameraTransform.eulerAngles.y,
ref turnSmoothVelocity,
GetModifiedSmoothTime(data.TurnSmoothTime));
}
data.CurrentMovementSpeed = Mathf.SmoothDamp( /* Set the movementspeed */
data.CurrentMovementSpeed,
data.MovementSpeed * inputDirection.magnitude,
ref speedSmoothVelocity,
GetModifiedSmoothTime(data.SpeedSmoothTime));
data.VelocityY += data.PlayerGravity * Time.deltaTime; // vertical velocity
Vector3 velocity = transform.forward * data.CurrentMovementSpeed + Vector3.up * data.VelocityY; // set the players velocity
data.PlayerCharacterController.Move(velocity * Time.deltaTime); // Move the player
data.CurrentMovementSpeed = (new Vector2(data.PlayerCharacterController.velocity.x, data.PlayerCharacterController.velocity.z)).magnitude; // Calc movementspeed
if (data.PlayerCharacterController.isGrounded) // Set the vertical vel. to 0 when grounded
data.VelocityY = 0;
}
float GetModifiedSmoothTime(float smoothTime) // Handle the movement while in air
{
if (data.PlayerCharacterController.isGrounded)
return smoothTime;
if (data.AirControlPercentage == 0)
return float.MaxValue;
return smoothTime / data.AirControlPercentage;
}
}
So it seems obvious to replace all the CharacterController variables with a Rigidbody key word. But when it comes to
data.PlayerCharacterController.Move(velocity * Time.deltaTime);
I don't know what to replace there. When I got no CC but a Collider and a Rigidbody i drop through the ground. This may happen because of the code..
Could someone help me out?
Remove CharacterController component from your player and attach a Rigidbody component. Then use
GetComponent<Rigidbody>().velocity = velocity * Time.deltaTime;
I will suggest that you create a reference of you attached rigidbody and use it instead of GetComponent.

Categories

Resources