Hey Unity!
I am currently working on my first little game where the player is a squirrel. And I have gotten stuck with my player movement script.
The goal of my script is:
- The squirrel needs to be aligned with the ground/object it is climbing. (see the CastRay())
- The squirrel needs to be able to climb in trees (and maybe eventually the bad guys) and hang upside down from branches.
My current problems are:
- I want the forward of the squirrel gameobject based on the walking direction in relation to the camera and the slope it is walking on. So walking backwards (towards the camera) turns the squirrel gameobject 180 degrees. Even on sloped surfaces.
- I am able to let the squirrel walk around a horizontal cylinder, but when it reaches a 90 degree forward it gets stuck. Walking backwards works fine.
If anything is unclear or you maybe have a suggestion, please let me know!
Here is my full code:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
Animator animator;
CharacterController controller;
[SerializeField] Transform Cam;
[SerializeField] Transform surfaceCheck;
[SerializeField] Transform render;
Transform activeCamera;
[SerializeField] LayerMask surfaceMask;
[SerializeField] float turnSpeed = 0.1f;
[SerializeField] float walkSpeed = 5f;
[SerializeField] float gravity = -9.81f;
[SerializeField] float RaycastLength = 0.7f;
[SerializeField, Range(0.5f, 1f)] float RaycastSpread = 0.7f;
Quaternion rot;
float surfaceDistance = 0.05f;
float turnSmoothVelocity;
[SerializeField] bool applyGravity = true;
bool isGrounded;
Vector3 gVelocity;
Vector3 rotationDir;
Vector3 normal;
void Awake()
{
animator = GetComponent<Animator>();
controller = GetComponent<CharacterController>();
activeCamera = Cam;
rotationDir = transform.eulerAngles;
rot = Quaternion.Euler(rotationDir.x, rotationDir.y, rotationDir.z);
}
private void Update()
{
//Get input
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
Vector3 dir = new Vector3(horizontal, 0f, vertical).normalized;
bool hasHorizontalInput = !Mathf.Approximately(horizontal, 0f);
bool hasVerticalInput = !Mathf.Approximately(vertical, 0f);
bool isWalking = hasHorizontalInput || hasVerticalInput;
Vector3 _rotationDir = rotationDir.normalized;
//transform.RotateAround(transform.position, transform.up, 50 * Time.deltaTime);
if (isWalking)
{
//transform.rotation = Quaternion.Euler(rotationDir.x, transform.rotation.y, rotationDir.z);
//Rotate the moveDir to the same plane as rotationDir
Vector3 _dir = rot * dir;
float targetAngle = Mathf.Atan2(_dir.x, _dir.z) * Mathf.Rad2Deg;
float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSpeed);
//render.transform.rotation = Quaternion.Euler(0f, angle, 0f);
//Vector3 moveDir = (Quaternion.Euler(0f, targetAngle, 0f));
controller.Move(_dir.normalized * walkSpeed * Time.deltaTime);
}
CastRay(this.transform);
Gravity(applyGravity);
animator.SetBool("isWalking", isWalking);
}
private void OnDrawGizmos()
{
Gizmos.DrawSphere(surfaceCheck.position, surfaceDistance);
}
private void Gravity(bool applyGrav)
{
if (!applyGrav)
return;
isGrounded = Physics.CheckSphere(surfaceCheck.position, surfaceDistance, surfaceMask);
if (isGrounded && gVelocity.y < 0)
{
gVelocity.y = -0.01f;
}
else
{
gVelocity.y += gravity * Time.deltaTime;
}
Vector3 gravDir = rot * gVelocity;
controller.Move(gravDir * Time.deltaTime);
}
void CastRay(Transform castpoint)
{
LayerMask maskPlayer = LayerMask.GetMask("Player");
maskPlayer = ~maskPlayer;
RaycastHit hit;
for (float castAngle = 0; castAngle > -RaycastSpread; castAngle -= 0.1f)
{
Vector3 castDir = rot * (new Vector3(0f, castAngle, 1f));
Debug.DrawRay(castpoint.transform.position, castDir * RaycastLength, Color.cyan);
if (Physics.Raycast(castpoint.transform.position, castDir, out hit, RaycastLength, maskPlayer))
{
if (normal != hit.normal)
{
normal = hit.normal;
transform.rotation = Quaternion.FromToRotation(transform.up, hit.normal) * transform.rotation;
}
//Debug.Log("hit");
Debug.DrawRay(castpoint.transform.position, castDir * hit.distance, Color.yellow);
Debug.DrawRay(hit.point, normal * 2f, Color.red);
}
}
}
}