- Home /
How do I keep the player from automatically changing direction?
Hey all -
So I'm experimenting with some different third-person movement inputs. I have both a point and click to move character sort of working and a platform input character (WASD keyboard movement...just the Platform Input Controller slightly modified). This is all working through the locomotion system, so the movement is properly animating the character (albeit roughly).
I'm doing a fixed camera sort of idea (think the original Resident Evil), and when the character passes through a trigger, the camera changes to a different position (basically turns off the main camera and turns on a different main camera that is positioned differently).
Here's my issue. When the player triggers the camera change and I'm still "moving" the character (just holding down on W), the character will automatically spin around and change direction. It seems as though the WASD movement (or sometimes the mouse to click movement) gets confused when the camera changes and it is basing the direction off of whatever the camera is seeing as opposed to what direction the character is moving in? How would I change this around...is this a transform.position = Vector3.zero problem?
Where would I look to see what's going on? Would this be the Character Motor, the Input Controller? Something else?
Thanks a bunch.
So, I think I need to cache the previous camera vector information for when the camera switches over to the other. How would one do that?
Answer by aldonaletto · Dec 02, 2012 at 11:32 AM
The WASD controls in the ThirdPersonController script are based on the main camera orientation: W goes in the camera's forward direction, D goes to its right direction, and so on - that's why the character changes direction when a new camera is selected.
Changing this would require extensive modifications in the original script - I suggest you to remove the scripts ThirdPersonController and ThirdPersonCamera and use a custom script to control both, the character and the camera.
The script below does basically what you want, and may serve as a starting point. It doesn't use multiple cameras - instead of this, the main camera is translated instantly to the pre-set positions when their associated triggers are entered. These positions are defined by empty objects tagged as "CameraPos", which contain only a box (or sphere) collider adjusted to the desired area.
That's the character script:
var walkSpeed: float = 4.0;
var runSpeed: float = 8.0;
var jumpSpeed: float = 8.0;
var turnSpeed: float = 90.0;
// animation names
var walk = "walk";
var run = "run";
var idle = "idle";
var jump = "jump_pose";
var walkLim: float = 0.2; // enters walk animation above this speed
var runLim: float = 5.0; // enters run animation above this speed
private var velY: float = 0.0; // current vertical velocity (used for gravity)
private var gravity: float = 10.0;
private var jumping = false;
private var controller: CharacterController;
private var trCam: Transform;
function Start(){
controller = GetComponent(CharacterController);
trCam = Camera.main.transform;
animation[jump].wrapMode = WrapMode.ClampForever;
}
function Update(){
// movement control: AD rotates, WS goes forth/back
transform.Rotate(0, Input.GetAxis("Horizontal") * turnSpeed * Time.deltaTime, 0);
var speed = walkSpeed; // select moving speed
if (Input.GetKey("left shift") || Input.GetKey("right shift")){
speed = runSpeed; // shift activates sprint
}
var moveVel = transform.forward * Input.GetAxis("Vertical") * speed;
if (controller.isGrounded){
jumping = false; // character landed: isn't jumping anymore
velY = 0;
if (Input.GetButton("Jump")){
velY = jumpSpeed;
jumping = true; // character started the jump
}
}
velY -= gravity * Time.deltaTime; // calculate gravity effect
moveVel.y = velY; // add it to the current movement velocity
controller.Move(moveVel * Time.deltaTime); // move the character
// animation
var vel = controller.velocity.magnitude; // base it on current velocity
if (jumping){ // jumping is prioritary!
animation.CrossFade(jump);
} else if (vel > runLim){ // if not jumping, check run...
animation.CrossFade(run);
} else if (vel > walkLim){ // else check walk...
animation.CrossFade(walk);
} else { // else go to idle
animation.CrossFade(idle);
}
}
// camera control
function LateUpdate(){
trCam.LookAt(transform); // always look at the character
}
function OnTriggerEnter(other: Collider){
if (other.tag == "CameraPos"){ // if entered a CameraPos trigger...
trCam.position = other.transform.position; // move camera to its position
}
}
Playing with the character script and this seems to work! I'll continue to tweak and massage to make it fit my needs a bit more, but I think it's the push I needed. I'm avoiding the camerapos stuff right now, simply because I have that particular element working right now and want to focus on one thing before I break another. :-D Thanks a bunch, Aldo! $$anonymous$$uch appreciated.
Quick Addendum (Not sure if these get lost after the question is "answered", but I'll try): How does the CameraPos get what it's focused on when it's triggered? I'm trying to frame things in a particular way, but it almost always initially focuses on the player's feet since I need a trigger volume that reaches where the player can walk through. It tracks the character properly and that's really cool, but I just want to figure out how to make sure I get some detailed fra$$anonymous$$g for that initial trigger.
In addition, I would still like to leverage my $$anonymous$$ainCameraSwitch script for when I want to do a big change in perspective/environement/etc...how would I tweak my current script to make sure it gets the cool character tracking when the switch is initialized. Here's my code for that particular script:
var camera1 : Camera; var camera2 : Camera;
private var startCamera : int = 1;
function OnTriggerEnter(other : Collider) { if(other.CompareTag("Player")) {
camera1.enabled = !camera1.enabled; camera1.gameObject.active = !camera1.gameObject.active; camera2.enabled = !camera2.enabled; camera2.gameObject.active = !camera2.gameObject.active; startCamera = startCamera == 2 ? 1 : 2;
}
}
Thanks a bunch! Hopefully, this gets seen. If not, I might make a new question to get visibility. :D
When a CameraPos trigger is entered, the character function OnTriggerEnter simply moves the camera to the CameraPos object position. The camera focus the character because the instruction LookAt(transform) in LateUpdate makes the camera aim to the player position. If you want different camera heights in each trigger, simply adjust the trigger vertical position.
Okay - that makes sense, thanks Aldo. Is there an easy method in which to set an OnTargetExit on the CameraPos trigger, so it would automatically go back to the previous camera location?
Also, do you know how I would make sure that the character tracking continues to work after I switch the $$anonymous$$ain Camera using my script that I posted above?
Thanks a lot, Aldo. I really appreciate it.
Answer by ZorNiFieD · Dec 02, 2012 at 05:23 AM
In the rigidbody component of your moving object, there is a Constraints area. You can check off either X Y or Z for Freeze Position or Freeze Rotation. In your case, I believe it is Rotation.
That didn't really seem to make much of a difference. Tried noodling around with multiple combinations of settings in the Constraints, but didn't come across anything that helped with this particular issue. I'll keep poking around.
No, the 3rd Person Controller is a character controller, not a rigidbody - there are no constraints for a character controller.
Your answer
Follow this Question
Related Questions
How to rotate camera diagonally over players shoulder while still facing towards players direction 0 Answers
WASD Controls not in-sync with camera? 1 Answer
Associate animations with keys 1 Answer
Moving camera around with GUI buttons 4 Answers
Camera interfering with character movement while locking on to enemy. 1 Answer