3D fps Game with gun adding recoil - c#

I wanted to add Guns with recoil to my 3d fps game. It worked but for some reason all the time when i look completely downwards i walk backwards or frontwards. This only happens when the gun is active.
The Gun Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GunScript : MonoBehaviour
{
[SerializeField] float Recoil = 500f;
[SerializeField] float TimeTillNextShoot;
[SerializeField] float Range = 100f;
[SerializeField] Transform GunTipposition;
[SerializeField] float recoilRadius = 100f;
public Camera PlayerCamera;
public Rigidbody rbPlayer;
private void Update()
{
Shoot();
}
public void Shoot()
{
if (Input.GetButtonDown("Fire1"))
{
RaycastHit hit;
if(Physics.Raycast(PlayerCamera.transform.position, PlayerCamera.transform.forward, out hit, Range))
{
Debug.Log(hit.transform.name);
Enemy Enemytarget = hit.transform.GetComponent<Enemy>();
if(Enemytarget != null)
{
Enemytarget.TakeDamage(true);
}
}
if (gameObject.CompareTag("ShotGun"))
{
Transform RecoilPosition = GunTipposition.transform;
rbPlayer.AddExplosionForce(Recoil, RecoilPosition.position, recoilRadius);
}
}
}
}
The player Movement:
// Some stupid rigidbody based movement by Dani
using System;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
[Header("Assignables")]
[Tooltip("this is a reference to the MainCamera object, not the parent of it.")]
public Transform playerCam;
[Tooltip("reference to orientation object, needed for moving forward and not up or something.")]
public Transform orientation;
[Tooltip("LayerMask for ground layer, important because otherwise the collision detection wont know what ground is")]
public LayerMask whatIsGround;
private Rigidbody rb;
[Header("Rotation and look")]
private float xRotation;
[Tooltip("mouse/look sensitivity")]
public float sensitivity = 50f;
private float sensMultiplier = 1.5f;
[Header("Movement")]
[Tooltip("additive force amount. every physics update that forward is pressed, this force (multiplied by 1/tickrate) will be added to the player.")]
public float moveSpeed = 4500;
[Tooltip("maximum local velocity before input is cancelled")]
public float maxSpeed = 20;
[Tooltip("normal countermovement when not crouching.")]
public float counterMovement = 0.175f;
private float threshold = 0.01f;
[Tooltip("the maximum angle the ground can have relative to the players up direction.")]
public float maxSlopeAngle = 35f;
private Vector3 crouchScale = new Vector3(1, 0.5f, 1);
private Vector3 playerScale;
[Tooltip("forward force for when a crouch is started.")]
public float slideForce = 400;
[Tooltip("countermovement when sliding. this doesnt work the same way as normal countermovement.")]
public float slideCounterMovement = 0.2f;
private bool readyToJump = true;
private float jumpCooldown = 0.25f;
[Tooltip("this determines the jump force but is also applied when jumping off of walls, if you decrease it, you may end up being able to walljump and then get back onto the wall leading to infinite height.")]
public float jumpForce = 550f;
float x, y;
bool jumping;
private Vector3 normalVector = Vector3.up;
[Header("Wallrunning")]
private float actualWallRotation;
private float wallRotationVel;
private Vector3 wallNormalVector;
[Tooltip("when wallrunning, an upwards force is constantly applied to negate gravity by about half (at default), increasing this value will lead to more upwards force and decreasing will lead to less upwards force.")]
public float wallRunGravity = 1;
[Tooltip("when a wallrun is started, an upwards force is applied, this describes that force.")]
public float initialForce = 20f;
[Tooltip("float to choose how much force is applied outwards when ending a wallrun. this should always be greater than Jump Force")]
public float escapeForce = 600f;
private float wallRunRotation;
[Tooltip("how much you want to rotate the camera sideways while wallrunning")]
public float wallRunRotateAmount = 10f;
[Tooltip("a bool to check if the player is wallrunning because thats kinda necessary.")]
public bool isWallRunning;
[Tooltip("a bool to determine whether or not to actually allow wallrunning.")]
public bool useWallrunning = true;
[Header("Collisions")]
[Tooltip("a bool to check if the player is on the ground.")]
public bool grounded;
[Tooltip("a bool to check if the player is currently crouching.")]
public bool crouching;
private bool surfing;
private bool cancellingGrounded;
private bool cancellingSurf;
private bool cancellingWall;
private bool onWall;
private bool cancelling;
public static PlayerMovement Instance { get; private set; }
void Awake()
{
Instance = this;
rb = GetComponent<Rigidbody>();
//Create a physic material with no friction to allow for wallrunning and smooth movement not being dependant
//and smooth movement not being dependant on the in-built unity physics engine, apart from collisions.
PhysicMaterial mat = new PhysicMaterial("tempMat");
mat.bounceCombine = PhysicMaterialCombine.Average;
mat.bounciness = 0;
mat.frictionCombine = PhysicMaterialCombine.Minimum;
mat.staticFriction = 0;
mat.dynamicFriction = 0;
gameObject.GetComponent<Collider>().material = mat;
}
void Start()
{
playerScale = transform.localScale;
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
readyToJump = true;
wallNormalVector = Vector3.up;
}
private void FixedUpdate()
{
Movement();
}
private void Update()
{
MyInput();
Look();
}
private void LateUpdate()
{
//call the wallrunning Function
WallRunning();
WallRunRotate();
}
private void WallRunRotate()
{
FindWallRunRotation();
float num = 12f;
actualWallRotation = Mathf.SmoothDamp(actualWallRotation, wallRunRotation, ref wallRotationVel, num * Time.deltaTime);
playerCam.localRotation = Quaternion.Euler(playerCam.rotation.eulerAngles.x, playerCam.rotation.eulerAngles.y, actualWallRotation);
}
/// <summary>
/// Find user input. Should put this in its own class but im lazy
/// </summary>
private void MyInput()
{
x = Input.GetAxisRaw("Horizontal");
y = Input.GetAxisRaw("Vertical");
jumping = Input.GetButton("Jump");
crouching = Input.GetKey(KeyCode.LeftControl);
//Crouching
if (Input.GetKeyDown(KeyCode.LeftControl))
StartCrouch();
if (Input.GetKeyUp(KeyCode.LeftControl))
StopCrouch();
}
private void StartCrouch()
{
transform.localScale = crouchScale;
transform.position = new Vector3(transform.position.x, transform.position.y - 0.5f, transform.position.z);
if (rb.velocity.magnitude > 0.2f && grounded)
{
if (grounded)
{
rb.AddForce(orientation.transform.forward * slideForce);
}
}
}
private void StopCrouch()
{
transform.localScale = playerScale;
transform.position = new Vector3(transform.position.x, transform.position.y + 0.5f, transform.position.z);
}
private void Movement()
{
//Extra gravity
rb.AddForce(Vector3.down * Time.deltaTime * 10);
//Find actual velocity relative to where player is looking
Vector2 mag = FindVelRelativeToLook();
float xMag = mag.x, yMag = mag.y;
//Counteract sliding and sloppy movement
CounterMovement(x, y, mag);
//If holding jump && ready to jump, then jump
if (readyToJump && jumping) Jump();
//Set max speed
float maxSpeed = this.maxSpeed;
//If sliding down a ramp, add force down so player stays grounded and also builds speed
if (crouching && grounded && readyToJump)
{
rb.AddForce(Vector3.down * Time.deltaTime * 3000);
return;
}
//If speed is larger than maxspeed, cancel out the input so you don't go over max speed
if (x > 0 && xMag > maxSpeed) x = 0;
if (x < 0 && xMag < -maxSpeed) x = 0;
if (y > 0 && yMag > maxSpeed) y = 0;
if (y < 0 && yMag < -maxSpeed) y = 0;
//Some multipliers
float multiplier = 1f, multiplierV = 1f;
// Movement in air
if (!grounded)
{
multiplier = 0.5f;
multiplierV = 0.5f;
}
// Movement while sliding
if (grounded && crouching) multiplierV = 0f;
//Apply forces to move player
rb.AddForce(orientation.transform.forward * y * moveSpeed * Time.deltaTime * multiplier * multiplierV);
rb.AddForce(orientation.transform.right * x * moveSpeed * Time.deltaTime * multiplier);
}
private void Jump()
{
if ((grounded || isWallRunning || surfing) && readyToJump)
{
MonoBehaviour.print("jumping");
Vector3 velocity = rb.velocity;
readyToJump = false;
rb.AddForce(Vector2.up * jumpForce * 1.5f);
rb.AddForce(normalVector * jumpForce * 0.5f);
if (rb.velocity.y < 0.5f)
{
rb.velocity = new Vector3(velocity.x, 0f, velocity.z);
}
else if (rb.velocity.y > 0f)
{
rb.velocity = new Vector3(velocity.x, velocity.y / 2f, velocity.z);
}
if (isWallRunning)
{
rb.AddForce(wallNormalVector * jumpForce * 3f);
}
Invoke("ResetJump", jumpCooldown);
if (isWallRunning)
{
isWallRunning = false;
}
}
}
private void ResetJump()
{
readyToJump = true;
}
private float desiredX;
private void Look()
{
float mouseX = Input.GetAxis("Mouse X") * sensitivity * Time.fixedDeltaTime * sensMultiplier;
float mouseY = Input.GetAxis("Mouse Y") * sensitivity * Time.fixedDeltaTime * sensMultiplier;
//Find current look rotation
Vector3 rot = playerCam.transform.localRotation.eulerAngles;
desiredX = rot.y + mouseX;
//Rotate, and also make sure we dont over- or under-rotate.
xRotation -= mouseY;
float clamp = 89.5f;
xRotation = Mathf.Clamp(xRotation, -clamp, clamp);
//Perform the rotations
playerCam.transform.localRotation = Quaternion.Euler(xRotation, desiredX, 0);
orientation.transform.localRotation = Quaternion.Euler(0, desiredX, 0);
}
private void CounterMovement(float x, float y, Vector2 mag)
{
if (!grounded || jumping) return;
//Slow down sliding
if (crouching)
{
rb.AddForce(moveSpeed * Time.deltaTime * -rb.velocity.normalized * slideCounterMovement);
return;
}
//Counter movement
if (Math.Abs(mag.x) > threshold && Math.Abs(x) < 0.05f || (mag.x < -threshold && x > 0) || (mag.x > threshold && x < 0))
{
rb.AddForce(moveSpeed * orientation.transform.right * Time.deltaTime * -mag.x * counterMovement);
}
if (Math.Abs(mag.y) > threshold && Math.Abs(y) < 0.05f || (mag.y < -threshold && y > 0) || (mag.y > threshold && y < 0))
{
rb.AddForce(moveSpeed * orientation.transform.forward * Time.deltaTime * -mag.y * counterMovement);
}
//Limit diagonal running. This will also cause a full stop if sliding fast and un-crouching, so not optimal.
if (Mathf.Sqrt((Mathf.Pow(rb.velocity.x, 2) + Mathf.Pow(rb.velocity.z, 2))) > maxSpeed)
{
float fallspeed = rb.velocity.y;
Vector3 n = rb.velocity.normalized * maxSpeed;
rb.velocity = new Vector3(n.x, fallspeed, n.z);
}
}
/// <summary>
/// Find the velocity relative to where the player is looking
/// Useful for vectors calculations regarding movement and limiting movement
/// </summary>
/// <returns></returns>
public Vector2 FindVelRelativeToLook()
{
float lookAngle = orientation.transform.eulerAngles.y;
float moveAngle = Mathf.Atan2(rb.velocity.x, rb.velocity.z) * Mathf.Rad2Deg;
float u = Mathf.DeltaAngle(lookAngle, moveAngle);
float v = 90 - u;
float magnitue = rb.velocity.magnitude;
float yMag = magnitue * Mathf.Cos(u * Mathf.Deg2Rad);
float xMag = magnitue * Mathf.Cos(v * Mathf.Deg2Rad);
return new Vector2(xMag, yMag);
}
//a lot of math (dont touch)
private void FindWallRunRotation()
{
if (!isWallRunning)
{
wallRunRotation = 0f;
return;
}
_ = new Vector3(0f, playerCam.transform.rotation.y, 0f).normalized;
new Vector3(0f, 0f, 1f);
float num = 0f;
float current = playerCam.transform.rotation.eulerAngles.y;
if (Math.Abs(wallNormalVector.x - 1f) < 0.1f)
{
num = 90f;
}
else if (Math.Abs(wallNormalVector.x - -1f) < 0.1f)
{
num = 270f;
}
else if (Math.Abs(wallNormalVector.z - 1f) < 0.1f)
{
num = 0f;
}
else if (Math.Abs(wallNormalVector.z - -1f) < 0.1f)
{
num = 180f;
}
num = Vector3.SignedAngle(new Vector3(0f, 0f, 1f), wallNormalVector, Vector3.up);
float num2 = Mathf.DeltaAngle(current, num);
wallRunRotation = (0f - num2 / 90f) * wallRunRotateAmount;
if (!useWallrunning)
{
return;
}
if ((Mathf.Abs(wallRunRotation) < 4f && y > 0f && Math.Abs(x) < 0.1f) || (Mathf.Abs(wallRunRotation) > 22f && y < 0f && Math.Abs(x) < 0.1f))
{
if (!cancelling)
{
cancelling = true;
CancelInvoke("CancelWallrun");
Invoke("CancelWallrun", 0.2f);
}
}
else
{
cancelling = false;
CancelInvoke("CancelWallrun");
}
}
private bool IsFloor(Vector3 v)
{
return Vector3.Angle(Vector3.up, v) < maxSlopeAngle;
}
private bool IsSurf(Vector3 v)
{
float num = Vector3.Angle(Vector3.up, v);
if (num < 89f)
{
return num > maxSlopeAngle;
}
return false;
}
private bool IsWall(Vector3 v)
{
return Math.Abs(90f - Vector3.Angle(Vector3.up, v)) < 0.05f;
}
private bool IsRoof(Vector3 v)
{
return v.y == -1f;
}
/// <summary>
/// Handle ground detection
/// </summary>
private void OnCollisionStay(Collision other)
{
int layer = other.gameObject.layer;
if ((int)whatIsGround != ((int)whatIsGround | (1 << layer)))
{
return;
}
for (int i = 0; i < other.contactCount; i++)
{
Vector3 normal = other.contacts[i].normal;
if (IsFloor(normal))
{
if (isWallRunning)
{
isWallRunning = false;
}
grounded = true;
normalVector = normal;
cancellingGrounded = false;
CancelInvoke("StopGrounded");
}
if (IsWall(normal) && (layer == (int)whatIsGround || (int)whatIsGround == -1 || layer == LayerMask.NameToLayer("Ground") || layer == LayerMask.NameToLayer("ground"))) //seriously what is this
{
StartWallRun(normal);
onWall = true;
cancellingWall = false;
CancelInvoke("StopWall");
}
if (IsSurf(normal))
{
surfing = true;
cancellingSurf = false;
CancelInvoke("StopSurf");
}
IsRoof(normal);
}
float num = 3f;
if (!cancellingGrounded)
{
cancellingGrounded = true;
Invoke("StopGrounded", Time.deltaTime * num);
}
if (!cancellingWall)
{
cancellingWall = true;
Invoke("StopWall", Time.deltaTime * num);
}
if (!cancellingSurf)
{
cancellingSurf = true;
Invoke("StopSurf", Time.deltaTime * num);
}
}
private void StopGrounded()
{
grounded = false;
}
private void StopWall()
{
onWall = false;
isWallRunning = false;
}
private void StopSurf()
{
surfing = false;
}
//wallrunning functions
private void CancelWallrun()
{
//for when we want to stop wallrunning
MonoBehaviour.print("cancelled wallrun");
Invoke("GetReadyToWallrun", 0.1f);
rb.AddForce(wallNormalVector * escapeForce);
isWallRunning = false;
}
private void StartWallRun(Vector3 normal)
{
MonoBehaviour.print("wallrunning");
//cancels all y momentum and then applies an upwards force.
if (!grounded && useWallrunning)
{
wallNormalVector = normal;
if (!isWallRunning)
{
rb.velocity = new Vector3(rb.velocity.x, 0f, rb.velocity.z);
rb.AddForce(Vector3.up * initialForce, ForceMode.Impulse);
}
isWallRunning = true;
}
}
private void WallRunning()
{
//checks if the wallrunning bool is set to true and if it is then applies
//a force to counter gravity enough to make it feel like wallrunning
if (isWallRunning)
{
rb.AddForce(-wallNormalVector * Time.deltaTime * moveSpeed);
rb.AddForce(Vector3.up * Time.deltaTime * rb.mass * 40f * wallRunGravity * -Physics.gravity.y);
}
}
}
I used a addForce funktion to add the recoil.Please help me.
This sentence is juist written because i need to add more details

Related

How to get a character to turn in the direction of the camera? [Unity3D]

I've hit a roadblock where when I move the camera, while moving, the character rotates on the spot however, their direction in where they are heading changes when I update the left thumbstick.
This is odd as updating it in Update doesn't work and forces the character to move in circles and placing it in a bit of script that updates with the right thumbstick is moved, causes the character to rotate and move in very different directions that what I want it to go in. This is temporarily fixed when I move the left thumbstick, updating the character's movement.
The controls for this are: Left Thumbstick - Move player, Right Thumbstick - Move camera, East Button - Jump, North Button - Run.
The goal is to allow the character to rotate themselves as well as their direction when I move the camera rather than them only updating their direction when I move the left thumbstick.
Before the code, these are the packages I'm currently using within Unity that effect this: Cinemachine & Input System.
Here's the movement code that this is effecting:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;
using UnityEngine.AI;
using UnityEngine.InputSystem;
public class PlayerMovement : MonoBehaviour
{
private DefaultControls controls;
[Header("Unity General")]
[SerializeField]
private CharacterController controller;
public Transform cameraTransform;
public InputActionReference cameraControl;
[Header("General Settings")]//Player movement.
public bool canMovePlayer;
private Vector2 currentMovementInput;
private Vector3 currentMovement;
private Vector3 currentRunMovement;
private bool isMovementPressed;
private bool isRunPressed;
[Space]//Animator stuff.
public Animator characterAnimator;
private int isWalkingHash;
private int isRunningHash;
[Space]//Player running speed & how fast the player will turn when going left or right.
public float rotationFactorPerFrame = 15.0f;
public float runMultiplier = 3.0f;
[Space]//Default gravity for when the player is falling and gravity for when the player is grounded.
public float gravity = -9.81f;
public float groundedGravity = -0.05f;
[Space]//Playing jumping.
public float initialJumpVelocity;
private bool isJumpPressed = false;
private float maxJumpHeight = 1f;
private float maxJumpTime = 0.5f;
private bool isJumping = false;
private int isJumpingHash;
private bool isJumpAnimating = false;
private void Start()
{
Cursor.lockState = CursorLockMode.Locked;
npcInteraction = GetComponent<NPCInteraction>();
}
private void Awake()
{
controls = new DefaultControls();
controller = GetComponent<CharacterController>();
isWalkingHash = Animator.StringToHash("isWalking");
isRunningHash = Animator.StringToHash("isRunning");
isJumpingHash = Animator.StringToHash("isJumping");
controls.Movement.Walking.started += OnMovementInput;
controls.Movement.Walking.canceled += OnMovementInput;
controls.Movement.Walking.performed += OnMovementInput;
controls.Movement.Run.started += OnRun;
controls.Movement.Run.canceled += OnRun;
controls.Movement.Jump.started += OnJump;
controls.Movement.Jump.canceled += OnJump;
SetupJumpVariables();
}
private void SetupJumpVariables()
{
float timeToApex = maxJumpTime / 2;
gravity = (-2 * maxJumpHeight) / Mathf.Pow(timeToApex, 2);
initialJumpVelocity = (2 * maxJumpHeight) / timeToApex;
}
private void HandleJump()
{
if (!isJumping && controller.isGrounded && isJumpPressed)
{
characterAnimator.SetBool(isJumpingHash, true);
isJumpAnimating = true;
isJumping = true;
currentMovement.y = initialJumpVelocity * 0.5f;
currentRunMovement.y = (initialJumpVelocity + 0.5f) * 0.5f;
}
else if (!isJumpPressed && isJumping && controller.isGrounded)
{
isJumping = false;
}
}
private void OnJump(InputAction.CallbackContext context)
{
isJumpPressed = context.ReadValueAsButton();
}
private void OnRun(InputAction.CallbackContext context)
{
isRunPressed = context.ReadValueAsButton();
}
private void HandleRotation()
{
Vector3 positionToLookAt;
//Change in position our character should point to.
positionToLookAt.x = currentMovement.x;
positionToLookAt.y = 0.0f;
positionToLookAt.z = currentMovement.z;
//Current rotation of our character.
Quaternion currentRotation = transform.rotation;
if (currentMovementInput != Vector2.zero)
{
//Creates a new rotation based on where the player is currently pressing.
float targetAngle = Mathf.Atan2(currentMovementInput.x, currentMovementInput.y) * Mathf.Rad2Deg + cameraTransform.eulerAngles.y;
Quaternion targetRotation = Quaternion.Euler(0f, targetAngle, 0f);
transform.rotation = Quaternion.Lerp(currentRotation, targetRotation, rotationFactorPerFrame * Time.deltaTime);
}
}
private void OnMovementInput(InputAction.CallbackContext context)
{
currentMovementInput = context.ReadValue<Vector2>();
currentMovement = new Vector3(currentMovementInput.x, 0f, currentMovementInput.y);
currentRunMovement.x = currentMovementInput.x * runMultiplier;
currentRunMovement.z = currentMovementInput.y * runMultiplier;
MovementDirection();
isMovementPressed = currentMovementInput.x != 0 || currentMovementInput.y != 0;
}
private void MovementDirection()
{
currentMovement = cameraTransform.forward * currentMovement.z + cameraTransform.right * currentMovement.x;
currentMovement.y = 0f;
currentRunMovement = cameraTransform.forward * currentRunMovement.z + cameraTransform.right * currentRunMovement.x;
currentRunMovement.y = 0f;
}
private void HandleAnimation()
{
bool isWalking = characterAnimator.GetBool(isWalkingHash);
bool isRunning = characterAnimator.GetBool(isRunningHash);
if (isMovementPressed && !isWalking)
{
characterAnimator.SetBool(isWalkingHash, true);
}
else if (!isMovementPressed && isWalking)
{
characterAnimator.SetBool(isWalkingHash, false);
}
if ((isMovementPressed && isRunPressed) && !isRunning)
{
characterAnimator.SetBool(isRunningHash, true);
}
else if ((!isMovementPressed || !isRunPressed) && isRunning)
{
characterAnimator.SetBool(isRunningHash, false);
}
}
private void HandleGravity()
{
bool isFalling = currentMovement.y <= 0.0f;
float fallMultiplier = 1.5f;
if (controller.isGrounded)
{
characterAnimator.SetBool(isJumpingHash, false);
isJumpAnimating = false;
currentMovement.y = groundedGravity;
currentRunMovement.y = groundedGravity;
}
else if (isFalling)
{
float previousYVelocity = currentMovement.y;
float newYVelocity = currentMovement.y + (gravity * fallMultiplier * Time.deltaTime);
float nextYVelocity = (previousYVelocity + newYVelocity) * 0.5f;
currentMovement.y = nextYVelocity;
currentRunMovement.y = nextYVelocity;
}
else
{
float previousYVelocity = currentMovement.y;
float newYVelocity = currentMovement.y + (gravity * Time.deltaTime);
float nextYVelocity = (previousYVelocity + newYVelocity) * 0.5f;
currentMovement.y = nextYVelocity;
currentRunMovement.y = nextYVelocity;
}
}
// Update is called once per frame
public void Update()
{
HandleRotation();
HandleAnimation();
controller.Move(currentMovement * Time.deltaTime);
characterAnimator.SetFloat("Speed", controls.Movement.Walking.ReadValue<Vector2>().magnitude);
if (isRunPressed)
{
controller.Move(currentRunMovement * Time.deltaTime);
}
else
{
controller.Move(currentMovement * Time.deltaTime);
}
HandleGravity();
HandleJump();
if (cameraControl.action.triggered)
{
MovementDirection();
}
LockOnTarget();
Interaction();
}
private void OnEnable()
{
controls.Movement.Enable();
}
private void OnDisable()
{
controls.Movement.Disable();
}
}```
Before diving into your code that has quite deep stuff regarding the camara movement, find this simple way in which a gameObject can face the direction of the camera in a simple way. Just in case it helps. This answers directly your question "How to get a character to turn in the direction of the camera?"
using UnityEngine;
public class LookToCamForward : MonoBehaviour
{
void Start()
{
transform.rotation = Quaternion.LookRotation(Camera.main.transform.forward, Camera.main.transform.up);
}
}

How to make sliding mechanic gain speed when on a slope

I am a new unity developer that is trying to make a 3d game. So far I have managed to develop a pretty cool first-person character controller. It uses a character controller and it has sliding and jumping mechanics.
And the question is:
How can I make my player lose sliding speed when sliding up a slope and gain sliding speed when sliding down a slope?
Here is my code so far and please keep in mind that my code is messy and that I am a still beginner. If you need any further information please don't hesitate to ask. Thanks for your time! Also, any suggestions are more than welcome!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovementScript : MonoBehaviour
{
//Character controller refrence
private CharacterController controller;
//Camera refrence
[SerializeField] Camera fpsCam;
//IsGrounded variables
private float groundDistance = 1.5f;
public bool isGrounded;
//SomethingAbove variables
private float cellingDistance = 1.5f;
public bool somethingAbove;
//Variables
//Speed that is modified
private float speed = 12f;
//Default speed
private float baseSpeed = 12f;
//Slide speed that is modified
private float slideSpeed = 15f;
//Default slide speed
private float slideSpeedStorage = 15f;
//Crouch speed
private float crouchSpeed = 3f;
//Jump height
private float jumpHeight = 2f;
private bool isJumping = false;
//Gravity
private float gravity = -14.715f;
//Air resistance
private float xAirResistance = 0.5f;
private float zAirResistance = 0.35f;
//Air multipiler
private float airMultiplierJump = 1.1f;
//Fov
private float fovWhenSliding = 100f;
private float defaultFov;
//Crouch variables
float originalHeight;
float reducedHeight = 0.5f;
//Player input
float x;
float z;
bool jump;
bool control;
//Directions
Vector3 velocity;
private Vector3 move = new Vector3();
private Vector3 slideDirection = new Vector3();
private Vector3 jumpDirection = new Vector3();
private void Awake()
{
controller = GetComponent<CharacterController>();
}
private void Start()
{
//Getting the original height
originalHeight = controller.height;
//Getting the default fov
defaultFov = fpsCam.fieldOfView;
}
private void Update()
{
MyInput();
Calculations();
PlayerMovement();
}
private void MyInput()
{
//Getting WASD input
x = Input.GetAxis("Horizontal");
z = Input.GetAxis("Vertical");
//Space bar input
jump = Input.GetButtonDown("Jump");
//Left control input
control = Input.GetKey(KeyCode.LeftControl);
}
private void Calculations()
{
//Checking if player is grounded
Debug.DrawRay(transform.position, Vector3.down * groundDistance, Color.red);
isGrounded = Physics.Raycast(transform.position, Vector3.down, groundDistance);
//Checking if player can get up
Debug.DrawRay(transform.position, Vector3.up * cellingDistance, Color.black);
somethingAbove = Physics.Raycast(transform.position, Vector3.up, cellingDistance);
/*//Getting the player has enough speed and getting jump direction
if (isGrounded && jump && z > 0)
{
//If pressing W the jump direction is forward
jumpDirection = transform.forward;
}*/
//Movement in air
if (isGrounded)
{
//On ground movement
move = transform.right * x + transform.forward * z;
}
else
{
//If pressing W
if (z > 0)
{
//Jump direction multiplied by airMultiplierJump
move = transform.forward * z * airMultiplierJump + transform.right * x * xAirResistance;
}
else
{
//Jump direction = Vector3.zero;
move = transform.forward * z * zAirResistance + transform.right * x * xAirResistance;
}
}
//Checking if the player has enough speed for sliding and getting direction
if (Input.GetKeyDown(KeyCode.LeftControl) && isGrounded)
{
if (z == 1 || x == 1 || x == -1)
{
//If pressing W || A || D slide direction is the direction u are moving towards
slideDirection = transform.forward * z + transform.right * x;
}
else
{
//If pressing S the slide direction is zero
slideDirection = Vector3.zero;
}
}
//Adding extra force so the player stays on ground
if (isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}
//Calculating gravity
velocity.y += gravity * Time.deltaTime;
//Normalizing the move vector so the diagonal and normal movement are the same speed
if (move.sqrMagnitude > 1)
{
move.Normalize();
}
//Extra force on slope downwards so the player stays on it
if((x != 0 || z != 0) && OnSlope())
{
controller.Move(Vector3.down * controller.height / 2 * 2f);
}
}
private void PlayerMovement()
{
Jump();
Slide();
//Moving the player with WASD
controller.Move(move * speed * Time.deltaTime);
//Applying gravity
controller.Move(velocity * Time.deltaTime);
}
private void Slide()
{
//Checking for left control input and if the player is grounded
if(control && isGrounded && !OnSlope())
{
StartSlide();
}
//Checking if the player can uncrouch
else if(!somethingAbove && isGrounded)
{
StopSlide();
}
else if (!control)
{
controller.height = originalHeight;
speed = baseSpeed;
}
else if(control && !isGrounded)
{
controller.height = originalHeight;
speed = baseSpeed;
}
else
{
controller.height = reducedHeight;
speed = crouchSpeed;
}
}
//Starting to slide
private void StartSlide()
{
if (z != 1 || x != -1 || x != 1)
{
speed = crouchSpeed;
}
else
{
speed = 0f;
}
controller.height = reducedHeight;
controller.Move(slideDirection * Time.deltaTime * slideSpeed);
slideSpeed -= 10f * Time.deltaTime;
if (slideSpeed <= 0)
{
slideSpeed = 0f;
speed = crouchSpeed;
}
}
//Stopping the slide
private void StopSlide()
{
controller.height = originalHeight;
speed = baseSpeed;
//Slide speed recovery
slideSpeed = Mathf.Lerp(slideSpeed, slideSpeedStorage, Time.deltaTime * 2);
}
//Jumping mechanic
private void Jump()
{
if (jump && isGrounded)
{
isJumping = true;
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
}
}
private bool OnSlope()
{
if (isJumping)
{
return false;
}
RaycastHit hit;
if(Physics.Raycast(transform.position, Vector3.down, out hit, controller.height / 2 * 5f))
if(hit.normal != Vector3.up)
{
return true;
}
return false;
}
//Stopping the slide if hitting object
private void OnControllerColliderHit(ControllerColliderHit hit)
{
if(hit.transform.tag == "SlideStop")
{
slideSpeed = 0f;
speed = crouchSpeed;
}
}
}```
private bool OnSlope()
{
if (isJumping)
{
return false;
}
RaycastHit hit;
if(Physics.Raycast(transform.position, Vector3.down, out hit, controller.height / 2 * 5f))
if(hit.normal != Vector3.up)
{
return true;
}
return false;
}
One issue is comparing Vector3s which is bad practice, since they are arrays of floats. Even if the plane is completely planar, it might still return true due to what's known as 'floating point errors'. A better practice is to use:
Vector3.distance(hit.normal, Vector3.up) > .1f // or some other small value;

Touch to Zoom And Rotate script for Unity player

I had this unity player embedded in android studio activity.
It is a 3d model with animation, which I would like viewer to be able to zoom and view in different angle.
Script are from this link
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MobilemaxCamera : MonoBehaviour {
public Transform target;
public Vector3 targetOffset;
public float distance = 5.0f;
public float maxDistance = 20;
public float minDistance = .6f;
public float xSpeed = 5.0f;
public float ySpeed = 5.0f;
public int yMinLimit = -80;
public int yMaxLimit = 80;
public float zoomRate = 10.0f;
public float panSpeed = 0.3f;
public float zoomDampening = 5.0f;
private float xDeg = 0.0f;
private float yDeg = 0.0f;
private float currentDistance;
private float desiredDistance;
private Quaternion currentRotation;
private Quaternion desiredRotation;
private Quaternion rotation;
private Vector3 position;
private Vector3 FirstPosition;
private Vector3 SecondPosition;
private Vector3 delta;
private Vector3 lastOffset;
private Vector3 lastOffsettemp;
//private Vector3 CameraPosition;
//private Vector3 Targetposition;
//private Vector3 MoveDistance;
void Start() { Init(); }
void OnEnable() { Init(); }
public void Init()
{
//If there is no target, create a temporary target at 'distance' from the cameras current viewpoint
if (!target)
{
GameObject go = new GameObject("Cam Target");
go.transform.position = transform.position + (transform.forward * distance);
target = go.transform;
}
distance = Vector3.Distance(transform.position, target.position);
currentDistance = distance;
desiredDistance = distance;
//be sure to grab the current rotations as starting points.
position = transform.position;
rotation = transform.rotation;
currentRotation = transform.rotation;
desiredRotation = transform.rotation;
xDeg = Vector3.Angle(Vector3.right, transform.right);
yDeg = Vector3.Angle(Vector3.up, transform.up);
}
/*
* Camera logic on LateUpdate to only update after all character movement logic has been handled.
*/
void LateUpdate()
{
// If Control and Alt and Middle button? ZOOM!
if (Input.touchCount==2)
{
Touch touchZero = Input.GetTouch (0);
Touch touchOne = Input.GetTouch (1);
Vector2 touchZeroPreviousPosition = touchZero.position - touchZero.deltaPosition;
Vector2 touchOnePreviousPosition = touchOne.position - touchOne.deltaPosition;
float prevTouchDeltaMag = (touchZeroPreviousPosition - touchOnePreviousPosition).magnitude;
float TouchDeltaMag = (touchZero.position - touchOne.position).magnitude;
float deltaMagDiff = prevTouchDeltaMag - TouchDeltaMag;
desiredDistance += deltaMagDiff * Time.deltaTime * zoomRate * 0.0025f * Mathf.Abs(desiredDistance);
}
// If middle mouse and left alt are selected? ORBIT
if (Input.touchCount==1 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
Vector2 touchposition = Input.GetTouch(0).deltaPosition;
xDeg += touchposition.x * xSpeed * 0.002f;
yDeg -= touchposition.y * ySpeed * 0.002f;
yDeg = ClampAngle(yDeg, yMinLimit, yMaxLimit);
}
desiredRotation = Quaternion.Euler(yDeg, xDeg, 0);
currentRotation = transform.rotation;
rotation = Quaternion.Lerp(currentRotation, desiredRotation, Time.deltaTime * zoomDampening);
transform.rotation = rotation;
if (Input.GetMouseButtonDown (1))
{
FirstPosition = Input.mousePosition;
lastOffset = targetOffset;
}
if (Input.GetMouseButton (1))
{
SecondPosition = Input.mousePosition;
delta = SecondPosition - FirstPosition;
targetOffset = lastOffset + transform.right * delta.x*0.003f + transform.up * delta.y*0.003f;
}
////////Orbit Position
// affect the desired Zoom distance if we roll the scrollwheel
desiredDistance = Mathf.Clamp(desiredDistance, minDistance, maxDistance);
currentDistance = Mathf.Lerp(currentDistance, desiredDistance, Time.deltaTime * zoomDampening);
position = target.position - (rotation * Vector3.forward * currentDistance );
position = position - targetOffset;
transform.position = position;
}
private static float ClampAngle(float angle, float min, float max)
{
if (angle < -360)
angle += 360;
if (angle > 360)
angle -= 360;
return Mathf.Clamp(angle, min, max);
}
}
The zoom in and out work perfectly.
But the problem is, the rotate/pan is totally not working.
Anyone can give some help in this?
For the multi-touch, you have to use this script which I have given below.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MultiTouch: MonoBehaviour
{
float initialFingersDistance;
Vector3 initialScale;
float rotationRate = 0.2f;
int direction = 1;
void LateUpdate()
{
if (Input.touches.Length == 1)
{
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
Touch touch = Input.touches[0];
Quaternion desiredRotation = transform.rotation;
TouchLogic.Calculate();
if (Mathf.Abs(TouchLogic.turnAngleDelta) > 0)
{ // rotate
Vector3 rotationDeg = transform.eulerAngles;
rotationDeg.z = -TouchLogic.turnAngleDelta;
desiredRotation *= Quaternion.Euler(rotationDeg);
}
// not so sure those will work:
transform.rotation = desiredRotation;
// transform.Rotate(touch.deltaPosition.y * rotationRate, -touch.deltaPosition.x * rotationRate, 0, Space.World);
Vector3 rot = new Vector3(touch.deltaPosition.y * rotationRate, -touch.deltaPosition.x * rotationRate, transform.eulerAngles.z* rotationRate);
// transform.rotation = Quaternion.EulerAngles(rot);
}
}
else if (Input.touches.Length == 2)
{
Touch t1 = Input.touches[0];
Touch t2 = Input.touches[1];
if (t1.phase == TouchPhase.Began || t2.phase == TouchPhase.Began)
{
initialFingersDistance = Vector2.Distance(t1.position, t2.position);
initialScale = gameObject.transform.localScale;
}
else if (t1.phase == TouchPhase.Moved || t2.phase == TouchPhase.Moved)
{
var currentFingersDistance = Vector2.Distance(t1.position, t2.position);
// Debug.Log(currentFingersDistance);
////if (currentFingersDistance != initialFingersDistance)
//{
var scaleFactor = currentFingersDistance / initialFingersDistance;
gameObject.transform.localScale = initialScale * scaleFactor;
//}
float Dx = t1.position.x - transform.position.x;
float Dy = t1.position.y - transform.position.y;
//var cameraTransform = Camera.main.transform.InverseTransformPoint(0, 0, 0);
//transform.position = Camera.main.ScreenToWorldPoint(new Vector3(t2.position.x, t2.position.y, cameraTransform.z -0.5f));
Vector3 pos = t2.position;
//Vector3 pos = t1.position - t2.position;
Vector3 touchedPos = Camera.main.ScreenToWorldPoint(new Vector3(pos.x, pos.y, 10));
transform.position = Vector3.Lerp(transform.position, touchedPos, Time.deltaTime * 4);
// transform.position += touchedPos;
float pinchAmount = 0;
Quaternion desiredRotation = transform.rotation;
TouchLogic.Calculate();
if (Mathf.Abs(TouchLogic.pinchDistanceDelta) > 0)
{ // zoom
pinchAmount = TouchLogic.pinchDistanceDelta;
}
if (Mathf.Abs(TouchLogic.turnAngleDelta) > 0)
{ // rotate
Vector3 rotationDeg = Vector3.zero;
rotationDeg.z = -TouchLogic.turnAngleDelta;
desiredRotation *= Quaternion.Euler(rotationDeg);
}
// not so sure those will work:
transform.rotation = desiredRotation;
transform.position += Vector3.forward * pinchAmount;
}
}
}
}
For your touch control logic, you have to use this second script which I gave below.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TouchLogic: MonoBehaviour
{
const float pinchTurnRatio = Mathf.PI / 2;
const float minTurnAngle = 0;
const float pinchRatio = 1;
const float minPinchDistance = 0;
const float panRatio = 1;
const float minPanDistance = 0;
/// <summary>
/// The delta of the angle between two touch points
/// </summary>
static public float turnAngleDelta;
/// <summary>
/// The angle between two touch points
/// </summary>
static public float turnAngle;
/// <summary>
/// The delta of the distance between two touch points that were distancing from each other
/// </summary>
static public float pinchDistanceDelta;
/// <summary>
/// The distance between two touch points that were distancing from each other
/// </summary>
static public float pinchDistance;
/// <summary>
/// Calculates Pinch and Turn - This should be used inside LateUpdate
/// </summary>
///
static public Touch LastTouch;
static public void Calculate()
{
pinchDistance = pinchDistanceDelta = 0;
turnAngle = turnAngleDelta = 0;
// if two fingers are touching the screen at the same time ...
if (Input.touchCount == 1)
{
Touch touch1 = Input.touches[0];
turnAngle = Angle(touch1.position, LastTouch.position);
float prevTurn = Angle(touch1.position + touch1.deltaPosition,
LastTouch.deltaPosition + LastTouch.position);
turnAngleDelta = Mathf.DeltaAngle(prevTurn, turnAngle);
// ... if it's greater than a minimum threshold, it's a turn!
if (Mathf.Abs(turnAngleDelta) > minTurnAngle)
{
turnAngleDelta *= pinchTurnRatio;
}
else
{
turnAngle = turnAngleDelta = 0;
}
LastTouch =Input.touches[0];
}
else if (Input.touchCount == 2)
{
Touch touch1 = Input.touches[0];
Touch touch2 = Input.touches[1];
// ... if at least one of them moved ...
if (touch1.phase == TouchPhase.Moved || touch2.phase == TouchPhase.Moved)
{
// ... check the delta distance between them ...
pinchDistance = Vector2.Distance(touch1.position, touch2.position);
float prevDistance = Vector2.Distance(touch1.position - touch1.deltaPosition,
touch2.position - touch2.deltaPosition);
pinchDistanceDelta = pinchDistance - prevDistance;
// ... if it's greater than a minimum threshold, it's a pinch!
if (Mathf.Abs(pinchDistanceDelta) > minPinchDistance)
{
pinchDistanceDelta *= pinchRatio;
}
else
{
pinchDistance = pinchDistanceDelta = 0;
}
// ... or check the delta angle between them ...
turnAngle = Angle(touch1.position, touch2.position);
float prevTurn = Angle(touch1.position + touch1.deltaPosition,
touch2.position + touch2.deltaPosition);
turnAngleDelta = Mathf.DeltaAngle(prevTurn, turnAngle);
// ... if it's greater than a minimum threshold, it's a turn!
if (Mathf.Abs(turnAngleDelta) > minTurnAngle)
{
turnAngleDelta *= pinchTurnRatio;
}
else
{
turnAngle = turnAngleDelta = 0;
}
}
}
}
static private float Angle(Vector2 pos1, Vector2 pos2)
{
Vector2 from = pos2 - pos1;
Vector2 to = new Vector2(1, 0);
float result = Vector2.Angle(from, to);
Vector3 cross = Vector3.Cross(from, to);
if (cross.z > 0)
{
result = 360f - result;
}
return result;
}
}
Both scripts are used in a single project. using these scripts you can easily rotate your 3d object.
Note: Please attach this both script in a single 3d object, so you can use this script easily.

Clipping and zooming platformer

I am currently in the process of developing my first platformer, and I've decided that I want to bake my own acceleration and deceleration for movement instead of using unity's wonky physics.
This has brought up two roadblocks, one being that my character will just clip through objects like walls to jump over or off of, and the other is that if I try to switch directions while decelerating, my character will turn around, but it won't change directions and my acceleration will bypass the limit I set for it (in layman's, it zooms backwards).
I need help fixing this and can describe any of the functions of the variables if asked. There is no physics material on my character, and I am using physics for the jump.
All of the variables are defined in the unity editor for easier tweaking except for currentSpeed, jumpCount, FallTime and canJump, which I have serialized so I can observe them during testing.
I've tried changing
newPos = new Vector2(transform.position.x + currentSpeed, transform.position.y);
transform.position = newPos;
to addForce but it messed with the jumping.
public class PlayerControls : MonoBehaviour {
//walk Vars
[SerializeField] float currentSpeed;
[SerializeField] float maxSpeed;
[SerializeField] float jumpstart;
[SerializeField] float acceleration;
[SerializeField] float deceleraton;
int isFlip = 1;
Vector2 newPos;
Quaternion flip;
//jump Vars
[SerializeField] public int jumpCount;
[SerializeField] public int jumpCountMax;
[SerializeField] public float jumpVel;
[SerializeField] public float fallMulti;
[SerializeField] public float shortMulti;
[SerializeField] public float fallTime;
[SerializeField] public float coyoteTime;
[SerializeField] bool canJump = true;
[SerializeField] bool didJump;
//references
Rigidbody2D rb;
private void Awake() {
rb = GetComponent<Rigidbody2D>();
}
//walk Functions
private void speedCalc() {
currentSpeed += jumpstart * isFlip;
if (currentSpeed * isFlip >= maxSpeed) {
currentSpeed = maxSpeed * isFlip;
}
else {
currentSpeed = (currentSpeed * acceleration);
}
}
private void Start() {
currentSpeed = 0;
}
private void Update() {
//calculate coyote time
if (fallTime == coyoteTime) {
if (didJump == false) {
jumpCount += 1;
}
}
if (jumpCount >= jumpCountMax) {
canJump = false;
} else {
canJump = true;
}
if (rb.velocity.y == 0) {
jumpCount = 0;
didJump = false;
}
//calculate isFlip
if (Input.GetButton("Right")) {
flip = Quaternion.Euler(0, 0, 0);
transform.rotation = flip;
isFlip = 1;
} else if (Input.GetButton("Left")) {
flip = Quaternion.Euler(0, 180, 0);
transform.rotation = flip;
isFlip = -1;
}
//calculate acceleration & deceleration
if (!Input.GetButton("Right") && !Input.GetButton("Left")) {
if (currentSpeed * isFlip <= jumpstart) {
currentSpeed = 0;
} else {
currentSpeed = (currentSpeed / deceleraton);
}
} else {
speedCalc();
}
//implement falling and dyanamic jumping
if (rb.velocity.y < 0) {
fallTime += 1;
rb.velocity += Vector2.up * Physics2D.gravity * (fallMulti - 1) * Time.deltaTime;
} else if (rb.velocity.y == 0) {
fallTime = 0;
} else if (rb.velocity.y > 0 && !Input.GetButton("Jump")) {
rb.velocity += Vector2.up * Physics2D.gravity * (shortMulti - 1) * Time.deltaTime;
}
//execute jump
if (Input.GetButtonDown("Jump") && canJump == true) {
didJump = true;
rb.velocity = Vector2.up * jumpVel;
jumpCount += 1;
}
//move character position
newPos = new Vector2(transform.position.x + currentSpeed, transform.position.y);
transform.position = newPos;
}
}
There where no error messages or anything but I'm 80% sure its my logic and ordering. The acceleration might be overlapping with the deceleration and the isFlip.

How can i move the player randomly between the waypoints?

What i'm trying to do is once the random flag is true move the player between the waypoints randomly.
but just calling the random method is not enough.
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class Waypoints : MonoBehaviour
{
public GameObject[] waypoints;
public Transform target;
public float moveSpeed = 10f;
public float slowDownSpeed = 3f;
public float reverseSlowDownSpeed = 3f;
public float rotationSpeed = 1f;
private int targetsIndex = 0;
private Vector3 originalPosition;
private GameObject[] players;
public Transform reverseTarget;
private int reverseTargetsIndex = 0;
private Vector3 reverseOriginalPosition;
public bool random = false;
// Use this for initialization
void Start()
{
waypoints = GameObject.FindGameObjectsWithTag("Blocks");
players = GameObject.FindGameObjectsWithTag("Player");
originalPosition = players[0].transform.localPosition;
}
// Update is called once per frame
void Update()
{
if (random == true)
{
RandomWayPointsAI();
}
else
{
WayPointsAI();
}
}
private void WayPointsAI()
{
if (targetsIndex == waypoints.Length)
targetsIndex = 0;
target = waypoints[targetsIndex].transform;
float distance = Vector3.Distance(players[0].transform.position, target.transform.position);
players[0].transform.localRotation = Quaternion.Slerp(players[0].transform.localRotation, Quaternion.LookRotation(target.position - players[0].transform.localPosition), rotationSpeed * Time.deltaTime);
//move towards the player
if (distance < 30)
{
players[0].transform.localPosition += players[0].transform.forward * slowDownSpeed * Time.deltaTime;
}
else
{
players[0].transform.localPosition += players[0].transform.forward * moveSpeed * Time.deltaTime;
}
if (distance < target.transform.localScale.magnitude)
{
targetsIndex++;
}
}
private void ReverseWayPointsAI()
{
if (reverseTargetsIndex == 0)
reverseTargetsIndex = waypoints.Length - 1;
reverseTarget = waypoints[reverseTargetsIndex].transform;
float distance = Vector3.Distance(players[1].transform.position, reverseTarget.transform.position);
players[1].transform.rotation = Quaternion.Slerp(players[1].transform.rotation, Quaternion.LookRotation(reverseTarget.position - players[1].transform.position), rotationSpeed * Time.deltaTime);
//move towards the player
if (distance < 30)
{
players[1].transform.position += players[1].transform.forward * reverseSlowDownSpeed * Time.deltaTime;
}
else
{
players[1].transform.position += players[1].transform.forward * moveSpeed * Time.deltaTime;
}
if (distance < reverseTarget.transform.localScale.magnitude)
{
reverseTargetsIndex--;
}
}
void RandomWayPointsAI()
{
if (random == true)
{
int index = UnityEngine.Random.Range(0, waypoints.Length);
target = waypoints[index].transform;
}
}
void DrawLinesInScene()
{
// draw lines between each checkpoint //
for (int i = 0; i < waypoints.Length - 1; i++)
{
Debug.DrawLine(waypoints[i].transform.position, waypoints[i + 1].transform.position, Color.blue);
}
// draw a line between the original transform start position
// and the current transform position //
Debug.DrawLine(originalPosition, players[0].transform.position, Color.red);
Debug.DrawLine(reverseOriginalPosition, players[1].transform.position, Color.red);
// draw a line between current transform position and the next waypoint target
// each time reached a waypoint.
if (target != null)
Debug.DrawLine(target.transform.position, players[0].transform.position, Color.green);
if (reverseTarget != null)
Debug.DrawLine(reverseTarget.transform.position, players[1].transform.position, Color.green);
}
void AddColliderToWaypoints()
{
foreach (GameObject go in waypoints)
{
SphereCollider sc = go.AddComponent<SphereCollider>() as SphereCollider;
sc.isTrigger = true;
}
}
}
Inside the Update i'm checking if random is true then calling the RandomWayPointsAI(); but it's not moving the player it's just keep picking up each frame a new random waypoint but that's it.
void Update()
{
if (random == true)
{
RandomWayPointsAI();
}
else
{
WayPointsAI();
}
}
Here is your answer. First you are not writing the movement code in the random function and you are expecting it to move.
bool getNextRandom = true;
void RandomWayPointsAI()
{
if (random == true && getNextRandom)
{
int index = UnityEngine.Random.Range(0, waypoints.Length);
target = waypoints[index].transform;
getNextRandom = false;
}
float distance = Vector3.Distance(players[0].transform.position, target.transform.position);
players[0].transform.localRotation = Quaternion.Slerp(players[0].transform.localRotation, Quaternion.LookRotation(target.position - players[0].transform.localPosition), rotationSpeed * Time.deltaTime);
//move towards the player
if (distance < 30)
{
players[0].transform.localPosition += players[0].transform.forward * slowDownSpeed * Time.deltaTime;
}
else
{
players[0].transform.localPosition += players[0].transform.forward * moveSpeed * Time.deltaTime;
}
if (distance < target.transform.localScale.magnitude)
{
getNextRandom = true;
}
}
Further you can imporve the solution by moving the movement code to another function which will give you better control
public GameObject[] waypoints;
public Transform target;
public float moveSpeed = 10f;
public float slowDownSpeed = 3f;
public float reverseSlowDownSpeed = 3f;
public float rotationSpeed = 1f;
private int targetsIndex = 0;
private Vector3 originalPosition;
private GameObject[] players;
public Transform reverseTarget;
private int reverseTargetsIndex = 0;
private Vector3 reverseOriginalPosition;
public bool random = false;
public bool getNextRandom = true;
// Use this for initialization
void Start()
{
waypoints = GameObject.FindGameObjectsWithTag("Blocks");
players = GameObject.FindGameObjectsWithTag("Player");
originalPosition = players[0].transform.localPosition;
}
// Update is called once per frame
void Update()
{
if (random == true)
{
RandomWayPointsAI();
}
else
{
WayPointsAI();
}
}
private void WayPointsAI()
{
if (targetsIndex == waypoints.Length)
targetsIndex = 0;
target = waypoints[targetsIndex].transform;
if (MovePlayer())
targetsIndex++;
}
private void ReverseWayPointsAI()
{
if (reverseTargetsIndex == 0)
reverseTargetsIndex = waypoints.Length - 1;
reverseTarget = waypoints[reverseTargetsIndex].transform;
if (MovePlayer())
reverseTargetsIndex--;
}
void RandomWayPointsAI()
{
if (random == true && getNextRandom)
{
int index = UnityEngine.Random.Range(0, waypoints.Length);
target = waypoints[index].transform;
getNextRandom = false;
}
getNextRandom = MovePlayer();
}
bool MovePlayer()
{
float distance = Vector3.Distance(players[0].transform.position, target.transform.position);
players[0].transform.localRotation = Quaternion.Slerp(players[0].transform.localRotation, Quaternion.LookRotation(target.position - players[0].transform.localPosition), rotationSpeed * Time.deltaTime);
//move towards the player
if (distance < 30)
{
players[0].transform.localPosition += players[0].transform.forward * slowDownSpeed * Time.deltaTime;
}
else
{
players[0].transform.localPosition += players[0].transform.forward * moveSpeed * Time.deltaTime;
}
if (distance < target.transform.localScale.magnitude)
return true;
else
return false;
}
void DrawLinesInScene()
{
// draw lines between each checkpoint //
for (int i = 0; i < waypoints.Length - 1; i++)
{
Debug.DrawLine(waypoints[i].transform.position, waypoints[i + 1].transform.position, Color.blue);
}
// draw a line between the original transform start position
// and the current transform position //
Debug.DrawLine(originalPosition, players[0].transform.position, Color.red);
Debug.DrawLine(reverseOriginalPosition, players[1].transform.position, Color.red);
// draw a line between current transform position and the next waypoint target
// each time reached a waypoint.
if (target != null)
Debug.DrawLine(target.transform.position, players[0].transform.position, Color.green);
if (reverseTarget != null)
Debug.DrawLine(reverseTarget.transform.position, players[1].transform.position, Color.green);
}
void AddColliderToWaypoints()
{
foreach (GameObject go in waypoints)
{
SphereCollider sc = go.AddComponent<SphereCollider>() as SphereCollider;
sc.isTrigger = true;
}
}
If you look at your RandomWayPointsAI() function, it only defines the index and the target but don't have any code below it to move the player.
private void WayPointsAI()
{
if (targetsIndex == waypoints.Length)
targetsIndex = 0;
target = waypoints[targetsIndex].transform;
float distance = Vector3.Distance(players[0].transform.position, target.transform.position);
players[0].transform.localRotation = Quaternion.Slerp(players[0].transform.localRotation, Quaternion.LookRotation(target.position - players[0].transform.localPosition), rotationSpeed * Time.deltaTime);
void RandomWayPointsAI()
{
//No need to check if random is true anymore, you already checked when you run this function
int index = UnityEngine.Random.Range(0, waypoints.Length);
target = waypoints[index].transform;
//float distance = Vector3.Distance(players[0].transform.position, target.transform.position);
//players[0].transform.localRotation = Quaternion.Slerp(players[0].transform.localRotation, Quaternion.LookRotation(target.position - players[0].transform.localPosition), rotationSpeed * Time.deltaTime);**
}

Categories