I am currently in the process of prototyping a game, and have come quite a ways in learning from basically understanding nothing about how to move a character in a 3d space outside of “transform.translate” to knowing how to reference my game object’s rigidbody and detect nearby objects and their layers.
I fear even with the notable progress I’ve made over the last week, my code seems to run commands far more often than I think would be necessary but I’m unsure of what commands I could use to lift that burden. Any tips from C# experts. Anything I could change or do quicker a different more efficient way?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    [SerializeField] private LayerMask groundMask;
    [SerializeField] private LayerMask wallMask;
    public GameObject myPlayer;
    public BoxCollider2D boxDetector;
    public Rigidbody2D playerBody;
    public float speed;
    public float jumpSpeed;
    float safeSpace = .5f;
    float wallSpace = .2f;
    float test;
    private bool wallGrabbing;



    void Start()
    {
        boxDetector = transform.GetComponent<BoxCollider2D>();
        playerBody = GetComponent<Rigidbody2D>();
        jumpSpeed = 10f;
        wallGrabbing = false;
    }
    void Update()
    {
        RaycastHit2D raycastGround = Physics2D.BoxCast(boxDetector.bounds.center, boxDetector.bounds.size, 0f, Vector2.down, safeSpace, groundMask);
        RaycastHit2D raycastWallLeft = Physics2D.BoxCast(boxDetector.bounds.center, boxDetector.bounds.size, 0f, Vector2.left, wallSpace, wallMask);
        RaycastHit2D raycastWallRight = Physics2D.BoxCast(boxDetector.bounds.center, boxDetector.bounds.size, 0f, Vector2.right, wallSpace, wallMask);

        if (raycastGround.collider != null)
        {
            speed = .5f;

            if (Input.GetKey(KeyCode.LeftShift))
            {
                speed = 1.5f;
            }
            if (Input.GetKey(KeyCode.W))

            if (Input.GetKeyDown(KeyCode.W))
            {
                playerBody.velocity = new Vector3(playerBody.velocity.x, jumpSpeed);
            }
        }
        else  
        {
            speed = .25f;
        }

        if (raycastWallLeft.collider != null || raycastWallRight.collider != null)
        {
            if (Input.GetKey(KeyCode.Space))
            {
                playerBody.gravityScale = 0;
                playerBody.velocity = new Vector2(0, 0);
                wallGrabbing = true;

            }
            if (Input.GetKey(KeyCode.S) && wallGrabbing == true)
            {
                Debug.Log("Wawa");
                playerBody.velocity = new Vector2(0, -.8f);
            }
            
        }
        if (Input.GetKeyUp(KeyCode.Space) && wallGrabbing == true)
        {
            playerBody.gravityScale = 1.5f;
            wallGrabbing = false;
        }
        if (Input.GetKey(KeyCode.S))
        {
            if (raycastWallLeft.collider == null && raycastWallRight.collider == null)
            {
                playerBody.gravityScale = 1.5f;
                wallGrabbing = false;

                if (raycastGround.collider == null)
                {
                    playerBody.gravityScale = 2f;
                }
                else
                {
                    Debug.Log("You're Crouching");
                }
            }

        }

        if (Input.GetKey(KeyCode.A) && (speed * -7f) <= playerBody.velocity.x && wallGrabbing == false)
        {
            playerBody.AddForce(transform.right * -1f * speed);
        }

        if (Input.GetKey(KeyCode.D) && playerBody.velocity.x <= (speed * 7f) && wallGrabbing == false)
        {
            playerBody.AddForce(transform.right * speed);
        }
        Vector3 theScale = transform.localScale;
        theScale.x *= -1;

        if (playerBody.velocity.x <= 0f)
        {
            theScale.x = -2f;
            transform.localScale = theScale;
        }

        if (playerBody.velocity.x >= 0f)
        {
            theScale.x = 2f;
            transform.localScale = theScale;
        }
    }
}

Here would be my corrected code (and my explanation is below):

using CustomInspector;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    [SelfFill] public BoxCollider2D boxDetector;
    [SelfFill] public Rigidbody2D playerBody;

    //Layers
    [SerializeField, Layer] private int groundLayer;
    [SerializeField, Layer] private int wallLayer;

    //Speeds
    [Header("Speeds")]
    [SerializeField, Min(0.001f)]
    float maxSpeed = .7f;

    [SerializeField, Min(0), Tooltip("How fast maxWalkSpeed will be reached")]
    float walkHardness = 1;

    [SerializeField, Range(1, 4), Tooltip("how much is running faster than walking")]
    float runMultiplier = 2;

    [SerializeField, Range(.1f, .9f), Tooltip("gets multiplied on speed if he is mid air")]
    float airMultiplier = .25f;

    [SerializeField]
    float jumpForce = 10;

    //Collide infos
    [Min(0)] const float safeSpace = .5f;
    [Min(0)] const float wallSpace = .2f;

    // -
    bool wallIsGrabbed = false; //rename from wallGrabbing

    void Update()
    {
        Movement();
    }
    void Movement()
    {
        bool hitWall = Physics2D.BoxCast(boxDetector.bounds.center, boxDetector.bounds.size, 0f, Vector2.left, wallSpace, wallLayer).collider != null
                        || Physics2D.BoxCast(boxDetector.bounds.center, boxDetector.bounds.size, 0f, Vector2.right, wallSpace, wallLayer).collider != null;

        
        if(hitWall && (wallIsGrabbed || TryGrabWall()))
        {
            //Vertical Movement
            wallIsGrabbed = true;
            playerBody.velocity = Vector2.zero;

            if(!EndGrabWall())
            {
                playerBody.gravityScale = 0;
            }
            else
            {
                wallIsGrabbed = false;
                playerBody.velocity = new Vector2(0, -.8f);
            }
        }
        else
        {
            bool hitGround = Physics2D.BoxCast(boxDetector.bounds.center, boxDetector.bounds.size, 0f, Vector2.down, safeSpace, groundLayer).collider != null;

            //Horizontal Movement
            playerBody.gravityScale = 1;

            //Add force
            float currentForce = hitGround ?
                walkHardness
                : walkHardness * airMultiplier;

            float movDir = Input.GetAxis("Horizontal");
            if (Mathf.Abs( playerBody.velocity.x ) < maxSpeed)
                playerBody.AddForce(new Vector2( movDir  * currentForce, 0));

            //SpriteHandling
            Debug.LogWarning($"Sprite should change its facing based on {nameof(movDir)}");

            //Jump
            if (TryJump())
            {
                playerBody.AddForce(new Vector2(0, jumpForce));
            }

            //Crouch
            if(Input.GetKey(KeyCode.S))
            {
                Debug.LogException(new System.NotImplementedException("Crouching is not implemented yet"));
            }
        }
    }
    bool TryJump() => Input.GetKeyDown(KeyCode.W);
    bool TryGrabWall() => Input.GetKey(KeyCode.Space);
    bool EndGrabWall() => Input.GetKey(KeyCode.S);
}

this would look in the inspector like this (you can edit there only variables you can edit):

explanation:

first what a good compiler would tell you:

  • You don’t need line 42, because after that you test whether w was just pressed
  • line 16 float test; public GameObject myPlayer; both are unused variables
  • Line 19, 20 you can make const/readonly
  • Line 46 you accidentally used Vector3 instead of Vector2

I would work on the readability, so you too will find mistakes faster and think in a more structured way: Comments that explain what you do or at least you capsulate your requirements in functions. e.g. in the update function you call a method named MoveAround(). In this method I would build on an if query,
which is called

if(OnWall()) { <wallbehaviour> } else { <horizontal movement> }

because they are two completely different behaviors

I would not invert the transform to just invert the sprite. Make a right-looking and a left-looking sprite - then you don’t have such problems with the transform direction. Changing the sprites is still missing with you anyway.

in line 77 you test whether left and right wall touches - i think you mean an ‘or’

magic numbers in the code is an anti-pattern
better assign them above. you write eg

speed = .5f or playerBody.velocity = new Vector2(0, -.8f);

You could also create a variable which is wallSlideSpeed just like you did for jumpspeed

You should take a look at the unity attributes:
If wallSlideSpeed should then be in the range of .5f to .8f, then write that down as well.
Attributes are important for hints. [Range(.5f, .8f)] float wallSlideSpeed only allows special values in the inspector

I would also do things like Speed with

[Min(.001f)] float speed = 1;

limit because you don’t want negative values.

as a question for you: Do your public fields really have to be public? Wouldn’t a ‘[SerializeField] BoxCollider2D boxDetector’ do the same thing?
You should only set stuff public if you want to get it from other scripts.

Why do you set jumpSpeed to 10 in Start() and not right at the top of the field like you did with eg wallSpace.
Anything you do at runtime is performance technically worse.

@AndreaMar has already referred to character controllers. I personally think there are a lot of unnecessary features in it, which is why I personally don’t use it. What I
The new input system is often used instead. This already has an axis evaluation of the keyboard and you get a direction.
An alternative is of course to move the character with animations and root motion anyway,
but that is certainly going too far.
He also addressed trigger. I like the idea of looking at unity’s collision detection. Your normal BoxCollider already has an OnCollisionEnter, which gives you information about all collisions.
In this you can also check the collider object for a tag instead of a layer. You can also read out the direction of the collisions and much more.
But I will ignore that in the following to explain to you further what I would improve on the code if you go the same way

Since you don’t actually use the physical casts, just checking if they took place, I would prefer to store a boolean value as well

I can also recommend ‘Custom Inspector’:
So I would set playerBody = GetComponent() beforehand. GetComponent is slow and
you can also assign the variable in the inspector. I see your point though (which is probably why you did that),
that afterwards it is unclear in the inspector which values belong in there.
For example, I can [SelfFill] recommend, this searches in its own object automatically in the editor and not runtime with GetComponent<> for the reference
Then you never have to worry about these types of assignments again

LayerMask wallMask is definitely only one layer and not a mask, i.e. several:
So you can really only select one layer with [Layer] int wallMask in the Inspector per enum selection.

If you want jumpSpeed always to be a 10 you can set it readonly by attribute, too.

[ReadOnly] public float jumpspeed = 10; 

Then you know, at least in the inspector, that changes are not applied

Custom Inspector attributes are part of Asset (Custom Inspector | Utilities Tools | Unity Asset Store)

It’s unclear to me what you’re trying to achieve as I’m quite bad at reading other people’s code.

Are you just trying to detect what objects the player comes in contact with? And you’re trying to move the player according to keyboard inputs?

Why don’t you use a trigger to detect collisions? Or a character controller to move your character?

You’re also trying to scale a transform to a negative value so you can flip it? Just rotate it.