How would I code this in 3D?

Ok, let’s see if I can make this make sense…
So in a game I’m making, I’m trying to implement a wall jump mechanic using OnTrigger. It currently works, kind of, but it’s a bit janky. What I want my code to do is in OnTriggerEnter, I want it to detect where the wall is in relation to the player (whether it’s in front of you, behind you, to your right, etc.), and when you jump, it sends the player away from that wall. I currently have no idea how to code this in, so some help would be appreciated.
Here’s my code in case you need it:

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

public class PlayerController : MonoBehaviour
{
    [Header("Movement")]
    public bool isMoving;
    public bool isWallRunning;
    public float moveSpeed;

    public float groundDrag;

    public float jumpForce;
    public float wallJumpForce;
    public float dashForce;
    public float jumpCooldown;
    public float dashCooldown;
    public float airMultiplier;
    public bool readyToJump;
    public bool readyToDash;

    [Header("Keybinds")]
    public KeyCode jumpKey = KeyCode.Space;
    public KeyCode dashKey = KeyCode.Mouse1;

    [Header("Ground Check")]
    public bool grounded;

    [Header("Wall Check")]
    public bool clingToWall;

    [Header("Rope Check")]
    public bool grabRope;

    public Transform orientation;

    public Transform playerObj;

    float horizontalInput;
    float verticalInput;


    Vector3 moveDirection;

    Rigidbody rb;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
        rb.freezeRotation = true;
    }

    void Update()
    {
        MyInput();
        SpeedControl();

        if (rb.velocity.magnitude > 0)
        {
            isMoving = true;
        }
        else
        {
            isMoving = false;
        }

        if(grounded || clingToWall)
        {
            rb.drag = groundDrag;
        }
        else
        {
            rb.drag = 0;
        }

        if(clingToWall || grabRope)
        {
            rb.useGravity = false;
        }
        else
        {
            rb.useGravity = true;
        }

        if (clingToWall && !isMoving)
        {
            clingToWall = false;
        }
    }

    private void FixedUpdate()
    {
        MovePlayer();
    }

    private void MyInput()
    {
        horizontalInput = Input.GetAxisRaw("Horizontal");
        verticalInput = Input.GetAxisRaw("Vertical");

        if(Input.GetKeyDown(jumpKey) && readyToJump && grounded)
        {
            readyToJump = false;

            Jump();

            Invoke(nameof(ResetJump), jumpCooldown);
        }

        if(Input.GetKeyDown(jumpKey) && readyToJump && grabRope)
        {
            readyToJump = false;

            Jump();

            Invoke(nameof(ResetJump), jumpCooldown);
        }

        if(Input.GetKeyDown(jumpKey) && readyToJump && clingToWall)
        {
            readyToJump = false;

            WallJump();

            Invoke(nameof(ResetJump), jumpCooldown);
        }

        if(Input.GetKeyDown(dashKey) && readyToDash)
        {
            readyToDash = false;

            Dash();

            Invoke(nameof(ResetDash), dashCooldown);
        }
    }

    private void MovePlayer()
    {
        moveDirection = orientation.forward * verticalInput + orientation.right * horizontalInput;

        if (grounded)
        {
            rb.AddForce(moveDirection.normalized * moveSpeed * 10f, ForceMode.Force);
        }

        else if(!grounded)
        {
            rb.AddForce(moveDirection.normalized * moveSpeed * 10f * airMultiplier, ForceMode.Force);
        }
    }

    private void SpeedControl()
    {
        Vector3 flatVel = new Vector3(rb.velocity.x, 0f, rb.velocity.z);

        if(flatVel.magnitude > moveSpeed)
        {
            Vector3 limitedVel = flatVel.normalized * moveSpeed;
            rb.velocity = new Vector3(limitedVel.x, rb.velocity.y, limitedVel.z);
        }
    }

    private void Jump()
    {
        rb.velocity = new Vector3(rb.velocity.x, 0f, rb.velocity.z);

        rb.AddForce(transform.up * jumpForce, ForceMode.Impulse);
    }

    private void WallJump()
    {
        rb.velocity = new Vector3(rb.velocity.x, 0f, rb.velocity.z);

        rb.AddForce(playerObj.forward * -1f * wallJumpForce + transform.up * jumpForce, ForceMode.Impulse);
    }

    private void Dash()
    {
        rb.velocity = new Vector3(rb.velocity.x, 0f, rb.velocity.z);

        if (grounded)
        {
            rb.AddForce(moveDirection.normalized * moveSpeed * 10f * dashForce, ForceMode.Impulse);
        }

        else if(!grounded)
        {
            rb.AddForce(moveDirection.normalized * moveSpeed * 10f * airMultiplier * dashForce, ForceMode.Impulse);
        }
    }

    private void ResetJump()
    {
        readyToJump = true;
    }

     private void ResetDash()
    {
        readyToDash = true;
    }


    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Ground"))
        {
            grounded = true;
        }
        if (other.CompareTag("InteractWall")  && isMoving && !grounded)
        {
            clingToWall = true;
        }
        if ((other.CompareTag("Rope") && !clingToWall))
        {
            grabRope = true;
            rb.velocity = Vector3.zero;
        }
    }

    private void OnTriggerExit(Collider other)
    {
        if (other.CompareTag("Ground"))
        {
            grounded = false;
        }
        if (other.CompareTag("InteractWall") || !isMoving)
        {
            clingToWall = false;
        }
        if (other.CompareTag("Rope"))
        {
            grabRope = false;
        }
    }
}

When the player hits the jump button and they’re not on the ground then your script can do a short raycast or spherecast in 8 directions (north, east, south, west, northwest, northeast etc) to get the hit normals which you can then use to determine the jump direction.

Appreciate it!

So, uhh, how would I do that?

I would start with tutorials… probably two or three separate tutorials. This stuff is going to be a complex dance between the player’s actual controller and the collisions and trigger volumes authored into the scene content, certainly not suitable for exhaustive descriptions here in a tiny text box.

The basics will be a normal walk controller that is always looking to be swapped out with a wall run controller based on what it finds, and then the wall controller knows how to go back to normal controller when appropriate.

The wall run controller would know how to find wall normals and offset itself correctly, just the same way a normal walk controller finds the floor and offsets from it.

Everything else is really an implementation detail. :slight_smile:

Place the eight directions into an array and iterate through the array doing a raycast for each direction. Add all the hit normals together and then divide the result by 8 to give you the average direction. Then have your character jump in the average direction. Easy peasy!

You can do it!!