What you could do is give the climbable walls or areas a box collider which set as a trigger. Then you could have on your character
var climbing = false;
OnTriggerEnter(){
climbing = true;
//whatever other changes you want
}
OnTriggerExit(){
climbing = false;
}
Then in your Update() function, you could have an if statement to check if we are climbing, and if we are, move in one way, and if not, then move as you already have it moving. Probably the only changes we want to what you have are to ignore gravity (remove the line `moveDirection.y -= gravity * Time.deltaTime;`) and to map forward movement (`Input.GetAxis("Vertical")`) to upward movement:
moveDirection = Vector3(0, Input.GetAxis("Vertical"), 0);
It's not perfect by a long shot, but as a quick and dirty way of climbing a wall, it should be sufficient.
EDIT:
Ok, here is the full script that I came up with, based on your original script. It is commented heavily, which I used to explain the whys of what I did, so that if you need to change it you can understand what each part does.
This script requires a kinematic rigidbody, but it will automatically attach one to your gameObject, so don't worry about that. It also requires a box collider set to act as a trigger that is just slightly in front of the walls which are climbable. The trigger needs to have the tag set to "climbableWall" and it is very important. Without it, this won't be any different from what you have now.
I also cleaned a few things up which were unrelated to climbing, but I commented all of them, and tried to explain my reasoning.
So without further rambling, here it is:
//require the CharacterController and a Rigidbody (for trigger)
@script RequireComponent(CharacterController)
@script RequireComponent(Rigidbody)
//not how I would have done the animation assignment, but perfectly functional
var animation1: String = "idle";
var animation2: String = "walk";
var animation3: String = "run";
var animation4: String = "rotateAround";
//renamed walkSpeed to moveSpeed for clarity
//also added our rigidbody var which is required to trigger OnTriggerEnter events
var walk : float = 1.0;
var run : float = 4.0;
private var moveSpeed : float = 1.0;
private var gravity = 100.0;
private var moveDirection : Vector3 = Vector3.zero;
private var charController : CharacterController;
private var body : Rigidbody;
private var climbing : boolean;
function Start()
{
//assign our variables which link to other components, and set animation mode
charController = GetComponent(CharacterController);
body = GetComponent(Rigidbody);
body.isKinematic=true;
animation.wrapMode = WrapMode.Loop;
}
function Update ()
{
//We call Input.GetAxis a lot, so let's just call them once, and store the answer
var h : float = Input.GetAxis("Horizontal");
var v : float = Input.GetAxis("Vertical");
//reset our moveDirection variable each time, just to be safe
moveDirection = Vector3.zero;
if(climbing)
{
//we are climbing, so we use different movement rules
//we shall use much of the same structure that is laid out below, because it is a fundamentally good structure
//this is not really optimized, and there is probably a more compact way of accomplishing the same goal, but this is easy to follow.
//always use the walk speed
moveSpeed = walk;
if(v > .1)
{
//pushing forward
moveDirection.y = v * moveSpeed;
//in addition to moving updwards, let's push forwards
//if we are still on the wall, the wall will push back and this will not matter
//if we reach the top of the wall, this will allow us to move to standing on top of it, instead of getting stuck hovering over the trigger
moveDirection.z = v * moveSpeed;
//perhaps also a climbing animation?
}
else if(v < -.1)
{
//pushing backwards
//this is actually the case when we care if we are grounded
if(charController.isGrounded)//shorthand for == true, it's a boolean itself, after all
{
//we are already at the bottom of the wall, and should move backwards, away from the wall
moveDirection.z = v * moveSpeed;
}
else
{
//we are not at the bottom, and should move downwards
moveDirection.y = v * moveSpeed;
}
}
//now we do the same thing (more or less) with the horizontal axis, so that we can move sideways.
if(h > .1)
{
//we are pushing to the right nontrivially
moveDirection.x = h * moveSpeed;
}
else if(h < -.1)
{
//we are pushing left nontrivially
moveDirection.x = h * moveSpeed;
//we have these two separate instead of just comparing Mathf.Abs(h) > .1 in case you want to change the animation for right vs left
//if you don't add anything else, you might as well replace this if else with a single if(Mathf.Abs(h) > .1){ moveDirection.x = h * moveSpeed}
}
//it is actually possible to get here without triggering any of the above movement conditions.
//But if that is the case, then we are on a climbable wall and should not do anything
//if you do want to do something if we aren't moving, like play a wall idle animation, then let's use:
//if(moveDirection == Vector3.zero)
//{
//
//}
}
else
{
//we are not climbing, so see if we are on the ground or in the air
if(charController.isGrounded == true)
{
//if we are grounded, we process input
if(v > .1)
{
//if we are pushing forward in a nontrivial manner
if(Input.GetButton("Fire1"))
{
//if we are pressing the Fire1 button, which is apparently the run button
animation.CrossFade(animation3);
moveSpeed = run;
}
else
{
//we are not pressing the run button, so just walk (forward)
animation[animation2].speed = 1;
animation.CrossFade(animation2);
moveSpeed = walk;
}
}
else if(v < -.1)
{
//we are not pushing forward, so look if we are pushing backwards in a nontrivial manner
//we don't care about the run button, just walk
animation[animation2].speed = -1;
animation.CrossFade(animation2);
moveSpeed = walk;
}
else
{
// Plays Idle
//we were not pushing significantly in either direction
animation.CrossFade(animation1);
}
// Create an animation cycle for when the character is turning on the spot
//I restructured this collection of if statements. There wasn't anything wrong with how you had it, but changes I have made necessitated a change
//and I think it's prettier this way.
if(Mathf.Abs(v) < .1)
{
//if we are inside of our deadzone:
if(h > .1)
{
animation[animation4].speed = 1;
animation.CrossFade(animation4);
}
// Nota esta a inverter animacao fica melhor uma nova animacao
//the above comment means nothing to me :)
if(h < -.1)
{
animation[animation4].speed = -1;
animation.CrossFade(animation4);
}
}
//transform.eulerAngles.y += Input.GetAxis("Horizontal");
//I took out the above line because, from the script reference:
//Don't increment them, as it will fail when the angle exceeds 360 degrees. Use Transform.Rotate instead.
transform.Rotate(0, h ,0);
//we rotate around the y axis, but with less failure when we cross from 360 to 0
// Calculate the movement direction (forward motion)
//Let's apply the movement scalar here instead of after gravity, so that gravity is not effected by it.
moveDirection = Vector3(0,0, v * moveSpeed);
moveDirection = transform.TransformDirection(moveDirection);
//now on to apply gravity (obey gravity, it's the law)
}
//we just exited the if(grounded) loop, so if we are not grounded, then all we do is apply gravity
//and then apply the motion to the controller
//gravity is here because we only want to apply it if we are not climbing,
//but we don't care if we are grounded or not
moveDirection.y -= gravity * Time.deltaTime;
}
//we have just left the if(climbing) else structure, so all possible conditions will execute this next line, as it should be
charController.Move(moveDirection * Time.deltaTime);
}
function OnTriggerEnter(other : Collider)
{
//check to see what trigger we just set off. It is possible that we want to use other triggers than just our wall climbing one
//Triggers are useful, after all.
//we obviously need to match the tag on the climbable wall triggers to what we have here.
if (other.tag == "climbableWall")
{
//ok, so we hit our climbable wall trigger
climbing = true;
//we should face the wall directly, to make sideways movement work properly.
//this finds the point on the trigger that is closest to us and looks at it.
transform.LookAt(other.ClosestPointOnBounds(transform.position));
//we will then level it out, leaving only the y rotation. the x shouldn't be necessary, but it doesn't hurt.
transform.rotation.eulerAngles.z = 0;
transform.rotation.eulerAngles.x = 0;
}
}
function OnTriggerExit(other : Collider)
{
//again, check which trigger we just left
if(other.tag == "climbableWall")
{
climbing = false;
}
}