- Home /
Controller work differently with same code and objects, but in different position
Hello. I have the most bizarre bug and wonder if someone might know the solution.
CONTEXT
I wrote a controller for a 2.5D-ish platformer. It allows the character to:
Jump
Climb vertical pipes
Hang and "move hanging" along horizontal pipes
Crouch
Everything seems to work as intended ( I paste the full controller below). My colleague started to develop the test level (mainly using Pro Builder and some simple models imported from Blender) and reported to me a bizarre occurrence - if he moved more to the "right" of our map, the protagonist stopped grabbing the pipe to hang. No variables seemed to be different - the pipe was copied from earlier parts of the level, the code was the same no matter where it was executed.
We started experimenting, moving the whole level blockout left and right, and indeed we received different results. If we moved the level further left, the controller didn't grab event the first pipes, that always worked fine. Moving the blackout left or up seemed to fix the problem, but only partially.
PROBLEM
The same code with the same objects on the level seems to give different results with no apparent reason other than the location in the editor.
CODE
Main controller:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Controller : MonoBehaviour
{
private CharacterController controller;
private ComplexMovement tricks;
public float gravity = -9.806f;
//Movement variables
public Vector3 velocity;
public float speed;
//Jumping variables
public float jumpHeight;
public float fallMultiplier;
public float lowJumpMultiplier;
public bool isJumping;
//Ground and ceiling check variables and objects
public float groundDistance;
public float ceilingDistance;
public Transform groundChecker;
public Transform ceilingChecker;
public float ceilingHitMultiplier;
//Climbing variables
public bool canClimb;
public bool isClimbing;
private Vector3 canClimbDirectionZ = new Vector3(0, 0, 1);
public float sphereDiameter = 0.1f;
//Hanging variables
public bool canHang;
public bool isHanging;
private Vector3 canHangDirectionY = new Vector3(0, 1, 0);
public bool isGrounded = true;
public bool ceilingOverhead = false;
//Functional layers for interactions
public LayerMask Ground;
public LayerMask Climable;
public LayerMask Usable;
public Animator animator;
//resetting values
float resetSpeed;
float resetControllerHeight;
Vector3 resetControllerCenter;
float resetGroundDistance;
float resetGravity;
public Vector3 normalGroundCheck;
public Vector3 controllerOffsetY = new Vector3(0, 0.5f, 0);
public float speedCrouchingFactor = 0.5f;
public RaycastHit hit;
public object Translate { get; private set; }
void Start()
{
//Getting the controller component of the Protag
controller = GetComponent<CharacterController>();
tricks = GetComponent<ComplexMovement>();
animator = GetComponentInChildren<Animator>();
normalGroundCheck = groundChecker.transform.position;
//setting the reseters
resetSpeed = speed;
resetControllerHeight = controller.height;
resetControllerCenter = controller.center;
resetGroundDistance = groundDistance;
resetGravity = gravity;
}
void Update()
{
if(Input.GetKeyDown("r"))
{
SceneManager.LoadScene("Level0", LoadSceneMode.Single);
}
if (Input.GetButton("Crouch") && isGrounded)
{
Crouch();
}
else
{
ResetProperties();
}
//Setting current animation state
if ((Input.GetAxis("Horizontal") != 0))
{
animator.SetInteger("run", 1);
}
else if ((Input.GetAxis("Horizontal") == 0) && !isClimbing)
{
animator.SetInteger("run", 0);
}
//Ground check using the shape of a sphere.
isGrounded = Physics.CheckSphere(groundChecker.position, groundDistance, Ground);
//setting animator parameter equal to ground check
animator.SetBool("grounded", isGrounded);
//Raycast chosen over Sphere. Sphere blocked jumping near walls even when it was really small
ceilingOverhead = Physics.Raycast(ceilingChecker.position, Vector3.up,ceilingDistance);
canHang = Physics.Raycast(ceilingChecker.position, ceilingChecker.position + canHangDirectionY, 0.5f, Climable);
if (canHang && Input.GetButton("Interact"))
{
isHanging = true;
}
canClimb = Physics.SphereCast(ceilingChecker.position, sphereDiameter, canClimbDirectionZ, out hit, 1f, Climable);
if (canClimb && Input.GetButton("Interact"))
{
isClimbing = true;
}
//Script for interacting with objects
else if (Input.GetButton("Interact"))
{
Interact();
}
//Velocity.y must be reseted when jump is finished.
if (isGrounded && velocity.y < 0)
{
velocity.y = 0f;
}
//The jump input and checks. Slope limit make jumping near walls jitter-free.
if (Input.GetButtonDown("Jump") && isGrounded && !ceilingOverhead)
{
isJumping = true;
}
}
void FixedUpdate()
{
//Movement is applied in fixed update, because then physics just works.
Vector3 move = new Vector3(Input.GetAxis("Horizontal"), 0, 0);
if (velocity.y < 0)
{
velocity += Vector3.up * gravity * (fallMultiplier - 1) * Time.deltaTime;
}
else if (velocity.y > 0 && !Input.GetButtonDown("Jump"))
{
velocity += Vector3.up * gravity * (lowJumpMultiplier - 1) * Time.deltaTime;
}
//Calling complex movement
if(isClimbing)
{
tricks.climb();
if (Input.GetButton("Vertical"))
{
animator.SetInteger("run", 1);
}
else
{
animator.SetInteger("run", 0);
}
animator.SetBool("climbing", true);
transform.forward = new Vector3(1, 0, 0);
}
else if (isHanging)
{
tricks.hang();
if (Input.GetButton("Horizontal"))
{
animator.SetInteger("run", 1);
}
else
{
animator.SetInteger("run", 0);
}
turnPlayerInTheDirectionOfMovement(move);
animator.SetBool("hanging", true);
//transform.forward = new Vector3(1, 0, 0);
}
else if(isJumping)
{
Jump();
isJumping = false;
}
else
{
turnPlayerInTheDirectionOfMovement(move);
animator.SetBool("hanging", false);
animator.SetBool("climbing", false);
controller.Move(move * Time.deltaTime * speed);
}
velocity.y += gravity * Time.deltaTime;
//Finally applying movement over time
controller.Move(velocity * Time.deltaTime);
}
public void ResetProperties ()
{
controller.center = resetControllerCenter;
controller.height = resetControllerHeight;
gravity = resetGravity;
animator.SetBool("crouching", false);
groundDistance = resetGroundDistance;
speed = resetSpeed;
}
public void turnPlayerInTheDirectionOfMovement(Vector3 move)
{
if ((move != Vector3.zero))
{
transform.forward = move;
}
}
public void Jump()
{
controller.slopeLimit = 90.0f;
velocity.y += Mathf.Sqrt(jumpHeight * -2f * gravity);
if (ceilingOverhead)
{
velocity.y -= ceilingHitMultiplier * fallMultiplier;
}
}
public void Crouch()
{
controller.center = new Vector3(0, 0.5f, 0);
controller.height = 1;
groundDistance = 0.2f;
animator.SetBool("crouching", true);
speed = speedCrouchingFactor * resetSpeed;
}
public void Interact()
{
Usable usable;
RaycastHit useThisObject;
if (Physics.Raycast(ceilingChecker.position, canClimbDirectionZ, out useThisObject, 7f, Usable))
{
usable = useThisObject.collider.gameObject.GetComponent<Usable>();
usable.OnRayHit();
}
Debug.DrawRay(ceilingChecker.position, canClimbDirectionZ + new Vector3(0, 0, 4), Color.blue, 2f);
}
}
Climbing pipes and hanging on them:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ComplexMovement : MonoBehaviour
{
public CharacterController controller;
public Controller controllerScript;
public float climbSpeed = 4f;
public float hangSpeed = 3f;
private void Start()
{
controller = GetComponent<CharacterController>();
controllerScript = GetComponent<Controller>();
}
//Climbing method
public void climb()
{
//Debug.Log("JESTEM HARDKOREM");
//Ensuring that no other "force" apply to climbing object
controllerScript.velocity.y = 0f;
controllerScript.gravity = 0;
Vector3 move = new Vector3(0, Input.GetAxis("Vertical"), 0);
if (Input.GetButton("Crouch") || controllerScript.canClimb == false)
{
controllerScript.isClimbing = false;
controllerScript.ResetProperties();
}
if(Input.GetButton("Jump") && Input.GetButton("Horizontal") && !Input.GetButton("Vertical"))
{
controllerScript.isGrounded = true;
controllerScript.isClimbing = false;
controllerScript.ResetProperties();
controllerScript.Jump();
}
controller.Move(move * Time.deltaTime * climbSpeed);
}
//Hanging method
public void hang()
{
//Debug.Log("wiszenie i chodzenie");
//Ensuring that no other "force" apply to hanging object
controllerScript.velocity.y = 0f;
controllerScript.gravity = 0f;
Vector3 move = new Vector3(Input.GetAxis("Horizontal"), 0, 0);
if(Input.GetButton("Crouch") || controllerScript.canHang == false)
{
controllerScript.isHanging = false;
controllerScript.ResetProperties();
}
controller.Move(move * Time.deltaTime * hangSpeed);
}
}
Answer by Puchaczu · Nov 21, 2020 at 02:21 PM
Hey, we are continuing our work by moving whooole level to the "left" ( on x-axis), yet the question remains. I wonder if this is something that can come back far down the project pipeline and stop us once and for all. If anybody wants to receive any kind of details I would be more than happy to provide them, since we are totally lost.
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Too many bugs 0 Answers
Using Dictionaries to store and retrieve GameObjects? 1 Answer
Lock Object Position In Editor 1 Answer