- Home /
Restricting Movement within a cover system?
I'm trying to implement a cover system where you can sort of bind yourself to objects by pressing space, where the character will then Lerp to the object if it's within a certain range. The character then should only be able to move along the one axis of that object until he comes to the edge. I've gotten so far as to be able to get the player to lerp to the object, but I'm not quite sure how to make him "stick" to the cover or walk in a restricted manner along it. None of the cover objects I've used so far have anything but flat faces for now to keep it simpler. I searched a bit on the internet, but most of the solutions I found were either very vague or geared towards third person characters, which this is not. The character is first person, which is what's also proving to make it slightly more difficult. Here's the code I have so far to have the character lerp and take cover. So far it's only up to the point where the character lerps, and the inCover boolean is switched to true. It's not all the code, but it's what I consider to be most relevant to this. Honestly, the take cover script right now has almost nothing dealing with the restricted movement because I haven't much of a clue where to even start with that.
function Update()
{
var hit: RaycastHit;
if (Physics.Raycast(transform.position - Vector3(0, 0.5, 0), transform.forward, hit))
{
distance = hit.distance;
if (distance <= 5)
{
if (hit.transform.tag == "CoverCrouch")
{
if (hidden == true)
{
showGUI();
}
if (Input.GetKeyDown(KeyCode.Space))
{
startLerping();
inCover = true;
}
}
Then here is the movement script I have (both are attached to the player). I also want to be able to look in a restricted viewing range with the characters back against the wall with a mechanism that I'll implement after I get this down to peek over and fire over the cover. That's not too important in the context of this question but I'm including it for context.
function Update()
{
//handles movement forward and back and strafing
if (chController.isGrounded)
{
var moveDirection: Vector3 = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
moveDirection = transform.rotation * moveDirection;
moveDirection *= speed;
}
moveDirection.y -= gravity * Time.deltaTime;
chController.Move(moveDirection *Time.deltaTime);
//sprinting
if (Input.GetKey(KeyCode.LeftShift))
{
speed = sprintSpeed;
} else if (!Input.GetKey(KeyCode.LeftShift))
{
speed = walkSpeed;
}
//handles look rotation
yRotation += Input.GetAxis("Mouse X") * horizontalSensitivity;
xRotation -= Input.GetAxis("Mouse Y") * verticalSensitivity;
//stops player from viewing greater than 90 degrees
xRotation = Mathf.Clamp (xRotation, -90, 90);
//handles look smoothing
currentXRotation = Mathf.SmoothDamp(currentXRotation, xRotation, xRotationV, lookSmooth);
currentYRotation = Mathf.SmoothDamp(currentYRotation, yRotation, yRotationV, lookSmooth);
theCamera.transform.rotation = Quaternion.Euler(currentXRotation, currentYRotation, 0);
transform.rotation = Quaternion.Euler(0, currentYRotation, 0);
}
Thanks for any help you guys can give. I know it's a bit open-ended as of right now, but my concept of how to go about doing this right now is very hazy at best so any information is appreciated.
Ok, so I've gotten something, although this is restricted to the global axis of my player, which isn't exactly what I was going for, but it does take into account the local z axis of the object so that's something. here's a line of code I inserted into the Update function at the end in the take Cover script. I also had to create a variable called cover object to do so which I did in my if statement for getbuttondown. It doesn't yet account for the bounds of the edge of the object, but it does account for the depth at which the character sits behind cover and restricts movement in that dimmension. Note: I don't have a mechanism yet to disengage either, but that would simply involve chanign the boolean inCover back to false.
if (Input.Get$$anonymous$$eyDown($$anonymous$$eyCode.Space))
{
startLerping();
coverObject = hit.transform.gameObject;
inCover = true;
}
and here's the code line for actuallly restricting the movement. I had to do it outside of update and only call it in update so that the character had enough time to lerp before being restricted
if (inCover)
{
restrict$$anonymous$$ovement();
}
function restrict$$anonymous$$ovement()
{
yield WaitForSeconds(lerpTime + 0.1);
transform.position.z = coverObject.transform.localPosition.z - 1;
}
the one in the code is just due to the offset of the crouched position vs the objects center. Any comments, improvements, etc. are welcome
Answer by fuego_see_money · Jun 30, 2015 at 11:29 PM
I think the proper way to do this would be (physics experts correct me if Im wrong) getting the surface normal of the polygon you are colliding with, and from there the correct tangent, which would represent the axis (via a Vector3) that you want to "slide" your character around once in cover.
Here is an answer to a question someone else asked about getting a tangent from a normal.
Basically you should get the GameObject you are taking cover of, the surface normal of the polygon you are colliding with, and from there you can obtain the tangent vector to move your character on. This way you can always slide on the object, even if its not orthogonal to your world coordinates and rotation.
Thanks for the advice and this did help. I'll post the script for reference, but i think this is going to be nearer to a final product. I only have it so that one set of keys (a and d) let you move along it because it seems more intuitive to play considering that irl if you were standing with your back to a wall while taking cover, even if your head moved, you hips would stay parallel to the wall, so the movement is still more strafe-like. I also didn't include functionality for w and s because I couldn't think of a way to incorporate both sets of inputs right now anyway into the script :P. Thanks for the help and here's the revise part of the script
function restrict$$anonymous$$ovement()
{
//establishes normal reference to be applied to object later
var normal : Vector3 = new Vector3 (0, 1, 0);
//establishes tangnt vector based on the normal reference vector and the transform of the object
var tangent : Vector3 = Vector3.Cross(normal, coverObject.transform.forward);
//ensures no errors are acquired if the magnitude is 0
if (tangent.magnitude == 0)
{
tangent = Vector3.Cross(normal, Vector3.up);
}
//can only move after lerp is done
yield WaitForSeconds(lerpTime + 0.1);
//adjust movement to respond to the player differently
fpsController.moveDirection =-Input.GetAxis("Horizontal") * tangent;
fpsController.moveDirection = fpsController.moveDirection * fpsController.speed;
}
If you use transform.translate on code above, don't forget to use space world. It would save you trouble.
Your answer
Follow this Question
Related Questions
Make Lerp or other more fluid or continuous 3 Answers
How to use Lerp? 3 Answers
Horizontal axis not working after animation 1 Answer
Stopping Vector3.Lerp 3 Answers
Smooth and restrict rotations? 1 Answer