- Home /
Wall running using raycasting.
Hey I need help getting my player to snap to a certain place, that is like 1 unit away from the wall he is next to, while he is off the ground.
Here is my code:
using UnityEngine;
using System.Collections;
public class TP_Raycast : MonoBehaviour
{
public static TP_Raycast Instance;
//Creates a ray
private Ray ray;
//Creates a RaycastHit
private RaycastHit hit = new RaycastHit();
//Get this GameObject's transform
private Transform playerTrans;
void Awake()
{
//get this Transform
playerTrans = this.GetComponent<Transform>();
}
// Update is called once per frame
void Update ()
{
//Ray to the left of player
//recreate the ray every frame AND draw debug line for the ray
ray = new Ray(playerTrans.position, transform.TransformDirection(Vector3.left));
Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.left), Color.green);
//Casts a ray to see if something has hit it
if(Physics.Raycast(ray.origin, ray.direction, out hit, 1))
{
//Collision has happened, print the distance and name of the object into the console
Debug.Log(hit.collider.name);
Debug.Log(hit.distance);
SnapToWalls();
}
else
{
//the ray isn't colliding with anything
Debug.Log("none");
}
}
void SnapToWalls()
{
//variable for the distance of the ray (never greater than 1)
var rayDist = hit.distance;
Debug.Log(rayDist);
//If the players raycasting hit a wall (always less than one if so)
if(rayDist > 0)
{
if(rayDist < 1)
{
//Only if player left the ground (jumped)
if(!TP_Controller.CharacterController.isGrounded)
{
//change gravity
TP_Motor.Gravity = 11f;
//then have the player forced forward somewhat (even if they dont push forward - more so if they do)
TP_Controller.CharacterController.Move(transform.TransformDirection(Vector3.forward) * Time.deltaTime * 2);
//and output blah into the console
Debug.Log("BLAH");
//HERE IS WHERE I NEED CODING TO MAKE MY PLAYER WALL WALK :(
}
}
}
else
{
//go back to normal
TP_Motor.Gravity = 21f;
}
}
}
what this does right now is move the player forwards a little, and if they are pressing forward it moves them faster, later ill animate the character like he is running along the wall.
but i need to make it like he is only moveable in two axis's of the world, or maybe only one, if he is going straight up a wall with a ray thats going forward detecting a wall.
for now I cant think of a way to do it, I tried clamping but couldnt quite figure it out, how to get the raw like world coordinates of my player then to force any (X or Z) to be stuck at a number I set. that way he moves sort of along the surface of a wall.
anyone know how the make my player move along a wall, still being effected by gravity from my motor? what are other ways to make that effect?
Ok, still the same issue. Since your "SnapToWalls" function depends on the RaycastHit struct, it doesn't make much sense to call it before your raycast and also it should only be called when you have a positive Raycast-hit, So you should call it inside your if(Raycast())
block. Everything else doesn't make sense.
About your second question (which should actually be a seperate question): I don't really understand what you want to achieve. What "scripted object"? - a rigidbody? - the player? What do you mean by "stuck at an axis's location"?
Do you mean that you want your player to run up a wall when you run straight into it? That sounds more like an artificial gravity problem to me.
The RaycastHit structure is filled by the Physics.Raycast function. You provide the "hit" variable as "out" parameter which is the same as "ref" but works only one-way.
Where do you think is the data in your hit struct com$$anonymous$$g from?
The data in "hit" is set by this line:
if(Physics.Raycast(ray.origin, ray.direction, out hit, 1))
// /|\
// |
// Here it is set
but "hit" contains only valid data when the raycast hit something and the Raycast function returned "true". Using hit before you call Raycast or when Raycast returns false doesn't make sense.
Ok, when Raycast returns true it does work, but you process the hit information from the last frame ins$$anonymous$$d of the information you get from the Raycast this frame.
I think I understand what your saying, while waiting for your response and after your answer at first I made some changes to the code, its more organised now I think, got rid of some redundancy I had done lol...can you update your answer with more info on what I should change? thanks for the help so far, I am pretty new to unity coding :)
Answer by huynhkhoa9 · Mar 19, 2012 at 05:35 AM
i think you should create a new function in TP_Motor called "MoveOnWall()" in this method you force the player into the wall(to create some friction),and then you CharacterController.Move to make him go upward. Also make the gravity 0 if necessary.
I appreciate your answer, which is similiar to what I ended up going with, although I haven't completed my script for wallrunning, I do have it somewhat functional.
What I did was cast three rays, to the left, forward and right, then wherever a ray hits an object that is totally 90 degrees straight up, align the direction necessary (if his left rays hitting, alight his left side to the wall yaknow) and disable player from strafing, and stop my camera from having my player align to its rotation. also I apply atleast some forward speed, so he cant just jump up and down straight up, as it would look weird having him animate sideways running and not move forward.
This works somewhat, but I am gonna refine it more later, and one problem now is that the player does align to the surface, but it is never an exact distance, as the rays are casting 1 unit long, if the hit happens when the player is rotated somewhat from the surface, it just rotates him right to a perpendicular spot, however the distance between him in the wall is almost always going to be > 1 unit away, so the animation will never be perfectly aligned unless I can conceive a way to have him keep exactly 1 unit between him and the wall his ray hits, and have the raycast 1.1 unit or something to that effect, making him always keep the right distance there...
anyway yeah your answer is closer to what I ended up doing, assigning vector3's to his movement according to the collision of the raycasts.
Answer by Bunny83 · Feb 07, 2012 at 06:48 PM
I'm not sure how you use the Raycast function since it's not in the code you've posted. Just to make sure you understand how the raycast function works: Raycast returns a boolean which is true when the ray hits something or false what it doesn't. If the Raycast function returns false the data in your RaycastHit structure contains garbage since there was no hit. If you raycast only 1 unit it will almost never report a hit at 1 unit distance.
I guess your "else" block should be the else of your if (Raycast(...))
block