Page 1 of 2

Headbob script not working right

Posted: Sun Mar 25, 2018 4:35 am
by MeteoricDragon
This is my first unity script function and it doesn't work right. I'm trying to get the player's head to bob when walking.

I think that Time.deltaTime gives me time since last frame was rendered but I think I need actual time to test it.

private void BobCheck()
{
// TODO: add toggle variable for setting Head bobbing on/off
//if (HeadBobSetting == false)
// return;

float movementPerFrame = new Vector2(moveDirection.x, moveDirection.z).magnitude;
float horizontalVelocity = movementPerFrame / Time.deltaTime;

if (grounded && (horizontalVelocity > 0))
{
float bobOscillate = Mathf.Sin(Time.deltaTime * horizontalVelocity * (2 * Mathf.PI) );
bobOscillate = Mathf.Clamp(bobOscillate, 0.0f, 1.0f);

Debug.Log("bobOscillate = " + bobOscillate);

float headPos = eyeHeight;
headPos += bobOscillate;
Vector3 pos = mainCamera.transform.localPosition;
pos.y = (standingHeight / 2) - headPos;
mainCamera.transform.localPosition = pos;
controller.height = standingHeight;

}
}

Re: Headbob script not working right

Posted: Sun Mar 25, 2018 5:27 am
by Interkarma
Without going too deeply into rest of script, Time.deltaTime should be a multiplier (e.g. change = speed * Time.deltaTime).

But you're using it as a divisor in the first case (horizontalVelocity = movementPerFrame / Time.deltaTime) and then as a multiplier in the second (Time.deltaTime * horizontalVelocity). This is the same as just feeding movementPerFrame straight into your sin function without using deltaTime at all.

By all means experiment without using deltaTime. Work out the waveform sampling and changing camera position first, then work out making it frame-rate independent. It can be helpful as a learning exercise to further break down the problems like this until none remain.

Re: Headbob script in progress

Posted: Mon Mar 26, 2018 2:33 am
by MeteoricDragon
Hey! Thanks! I got it working kind of! The head does bob, but it needs adjustments. And it.. breaks crouching and riding

In order to allow it to work with crouching, cart riding, and horseback riding, I need to change the bobPosition variable I set to the current position of the player camera. Look at the line I bolded below in code. I set the player's initial bob position to the same position that the players head gets set to when he is standing.

private void BobCheck()
{
float bobbingSpeed = 0.18f;
float bobbingAmount = 0.16f;
float bobPosition = (standingHeight / 2) - eyeHeight;

float waveslice = 0.0f;
//float horizontal = Input.GetAxis("Horizontal");
//float vertical = Input.GetAxis("Vertical");
float horizontalVelocity = new Vector2(moveDirection.x, moveDirection.z).magnitude;

Vector3 pos = mainCamera.transform.localPosition;

if (horizontalVelocity == 0)
{
bobTimer = 0.0f;
}
else
{
waveslice = Mathf.Sin(bobTimer);
bobTimer += bobbingSpeed;
if (bobTimer > Mathf.PI * 2)
{
bobTimer -= (Mathf.PI * 2);
}
//Debug.Log("waveslice = " + waveslice + ", eyePosition = " + eyePosition + ", TimeDelta = " + Time.deltaTime + ", Bob: " + bobbingSpeed + ", Timer: " + bobTimer);
}
if (waveslice != 0)
{
float changeAmount = waveslice * bobbingAmount;

horizontalVelocity = Mathf.Clamp(horizontalVelocity, 0.0f, 1.0f);
changeAmount = horizontalVelocity * changeAmount;
pos.y = bobPosition - changeAmount;
}
else
{
pos.y = bobPosition;
}

mainCamera.transform.localPosition = pos;
controller.height = standingHeight;

}

Re: Headbob script not working right

Posted: Mon Mar 26, 2018 2:54 am
by Interkarma
One possibility is to watch TransportManager.TransportMode (the TransportManager component is on Player object and available through GameManager.Instance) then change your base height depending on mode player is currently in.

A better idea might be to check PlayerMotor .isRiding / .isCrouching / .isClimbing etc. and adjust base height or disable bob as appropriate.

Also something to keep in mind is that PlayerMotor is scheduled for a major refactor in 0.5 at some point. This will be to clean up, improve design, and allow for moddable player movement states. Most of the current motor code will be thrown out or rewritten at this point. If you would like to submit your work on headbob as a PR later, please design to be a standalone MonoBehaviour if possible rather than edit into existing PlayerMotor script. This will allow headbob to be enabled/disabled independently and improve changes of making transition into motor refactor.

Keep it up! :)

Re: Headbob script not working right

Posted: Mon Mar 26, 2018 4:00 am
by MeteoricDragon
I like your suggestion of extending the headbobber from MonoBehavior. also, your other suggestions I like as well. I'm busy the next few days but will try those suggestions as I get time. Thanks!

Re: Headbob script not working right

Posted: Mon Mar 26, 2018 9:44 pm
by MeteoricDragon
Upon re-reading your post, what does PR stand for? Here in America it often stands for Public Relations, but that wouldn't make sense in this context :D

EDIT: nevermind, I figured it out. Public Release.

Re: Headbob script not working right

Posted: Mon Mar 26, 2018 9:49 pm
by Jay_H
Pull Request. It's a tool in github to transfer work from one user to another :)

Re: Headbob script not working right

Posted: Mon Mar 26, 2018 10:36 pm
by MeteoricDragon
Since I'm developing a class for Headbobber which extends MonoBehavior, how can I use that class's methods in DFU?

Do I call simply call them by instantiating a Headbobber instance in the playermotor class and calling methods from the instance there? or is there an easier way? If there's an update method in the headbobber class, does the instance I create in Playermotor simply start executing after being instantiated?

Re: Headbob script not working right

Posted: Mon Mar 26, 2018 11:12 pm
by Interkarma
What Jay said. :) PR in context of source repositories is a pull request where you send code to the master repository for the caretakers to check and merge when happy. You'll need to fork the main source code, create a branch of your own, add new work to that branch, then issue PR to my master when done. I might merge PR into a branch of its own on my end first for testing before it's merged to master. But no need to worry about that right now, it all comes at the end when you're ready to send changes my way.

Here's a high-level overview of executing that code in Unity.
  1. Create a new MonoBehaviour-derived class called HeadBobber (or whatever makes sense).
  2. Attach this component to PlayerAdvanced prefab (which will in turn add it to player instance in scene). The script will become active with player when game runs.
  3. In your headbob script Start() method, use GetComponent<PlayerMotor>() to cache a reference to the peered motor component on the player object.
  4. Then implement headbob logic and check the available fields & properties of playerMotor reference.
Let us know how you go!

Re: Headbob script not working right

Posted: Tue Mar 27, 2018 5:22 am
by MeteoricDragon
Great news.

I got the headbob script working correctly for crouch, walk, run, and horse. I have different amplitude and frequency settings for all 4, the side-to-side parabolic bob for each movement type can be tweaked independently of the up and down parabolic bob for each movement speed. The bobbing speed is synchronized to the player's footsteps(even when crouching). It also does some linear interpolation to transition smoothly between head bobbing and not bobbing and vice versa. It's separated into several virtual methods for mod overriding of the algorithm for the head bob. It's all in a separate class called HeadBobbing.

Next to allow user toggling of this. I should find out how to un-shade the headbobbing checkbox on the menu screen and allow player to click there if I can figure out what files need to be modified.