Forward and Sideways Player movement - unity3d

So my friends and I are developing a game where you play as a snowball rolling down a hill avoiding obstacles. We're having trouble with our movement, however. We want our snowball to gains speed the larger it gets and the longer it goes without hitting something. Our forward movement is controlled by
void FixedUpdate(){
rb.velocity += Physics.gravity * 3f * rb.mass * Time.deltaTime;
//to accelerate
rb.AddForce(0, 0, 32 * rb.mass);
}
We're applying a sideways force on key input
if (Input.GetKey(ControlManager.CM.left))
{
if (rb.velocity.x >= -15 - (rb.mass * 8))
{
rb.AddForce(Vector3.left * sidewaysForce * (rb.mass * .5f), ForceMode.VelocityChange);
}
}
if (Input.GetKey(ControlManager.CM.right))
{
if (rb.velocity.x <= 15 + (rb.mass * 8))
{
rb.AddForce(Vector3.right * sidewaysForce * (rb.mass * .5f), ForceMode.VelocityChange);
}
}
The mass increases as the scale increases and vice versa.
The issue comes when the snowball gets larger than a certain scale. Once it hits that point it massively accelerates left and right while you push the keys then snaps back to its forward speed when you let go. I assume it's something to do with the mass and the way the applied forces are compounding.
Is there a better way to accelerate our snowball downhill or move it left and right? I've tried transform.Translate and transform.MovePosition, but they lead to choppy left and right movement.

For one, most movement code should multiply the velocity by Time.deltaTime. In a hypothetical game, if you increased the velocity by a certain amount each frame, then somebody with a beefy 60 fps computer will go twice as fast as a poor 30 fps laptop gamer because they will accelerate less frequently. In order to fix this, we multiply acceleration by Time.deltaTime, which is the time since the last frame.
Instead of this code, where framerate would determine speed;
Vector3 example = new Vector3(1,1,1);
void Update()
{
rb.AddForce(example);
}
We would use this code. If the framerate is half as much, Time.deltaTime will be twice as much, so the acceleration will be constant for everyone using it.
Vector3 example = new Vector3(1,1,1);
void Update()
{
rb.AddForce(example * Time.deltaTime);
}
There may be another source of this problem, although getting rid of frame-rate dependencies is a good place to start. It looks like you already have used Time.deltaTime for downward velocity, but not for sideways movement. Even if it doesn't fix the problem, using Time.deltaTime is essential for any consistent game.

Related

Unity rope swinging physics algorithm: Player stuck mid-swing

I have implemented the following tutorial in Unity (2D) attempting to create a rope swinging platformer: https://gamedevelopment.tutsplus.com/tutorials/swinging-physics-for-player-movement-as-seen-in-spider-man-2-and-energy-hook--gamedev-8782
void FixedUpdate()
{
Vector2 testPosition = playerRigidbody.position + playerRigidbody.velocity * Time.deltaTime;
Hooked(testPosition);
}
private void Hooked(Vector2 testPosition)
{
Vector2 t = new Vector2(tetherPoint.position.x, tetherPoint.position.y);
Debug.DrawLine(tetherPoint.position, playerRigidbody.position);
float currentLength = (testPosition - t).magnitude;
if (currentLength < tetherLength)
{
currentLength = (playerRigidbody.position - t).magnitude * Time.deltaTime;
}
else
currentLength = tetherLength;
if ((testPosition - t).magnitude > tetherLength)
{
Vector2 x = (testPosition - t).normalized;
testPosition = new Vector2(x.x * currentLength, x.y * currentLength);
playerRigidbody.velocity = (testPosition - playerRigidbody.position) * Time.deltaTime;
playerRigidbody.position = testPosition;
}
}
It seems to function correctly on the downward swing but when the player begins to travel upwards they become stuck floating in the air and don't drop to the middle of the arc. The swing also does not propel them very high on the other side even when dropped from height.
EDIT (Further clarification): Interestingly When the player is dropped from the other side of the tetherPoint it stops in the same spot, this time only half-way down. It's as if the player is being pulled toward a single position even when manually moved in the editor while playing no matter the direction.
EDIT: User John cleared up my concerns about deltaTime.
I've tried examining the change in variables during play but I just can't figure out why it's not working correctly. I think the issue lies somewhere in my interpretation of the original psudeo-code to C#.
Another question on the same tutorial has been asked previously but unfortunately that users implementation was very different than mine: Game rope swing physics acting weird
EDIT: Since posting I've updated the code to use AddForce and MovePosition instead but it's still the same.
playerRigidbody.AddForce((testPosition - playerRigidbody.position) * Time.deltaTime);
playerRigidbody.MovePosition(testPosition);
It looks like you're using Time.deltaTime from a method that is called from FixedUpdate. What you want to use instead is Time.fixedDeltaTime.
FixedUpdate is called at a set interval (eg. 50fps) for physics updates, but regular Update is called at a different varying frequency (up to hundreds of times a second if you've got a fast computer/simple game).
Time.deltaTime is used for the Update method, and so the value of it can be different each time Update is called, as the time between Update calls varies.
However, because FixedUpdate is called at the same interval each time, Time.fixedDeltaTime is constant and (normally) much larger than Time.deltaTime. Your code doesn't work well with Time.deltaTime, as it doesn't represent the actual difference in time between each FixedUpdate call, but Time.fixedDeltaTime should work.
As a side note, you're correct that you should be multiplying by the time delta rather than dividing. the time delta should be multiplied when calculating positions (eg. for the Vector2 testPosition assignment and the currentLength calculation), but for calculating the velocity you should be dividing the time delta (because velocity = distance/time).

Unity3d, moving the player forward

Good evening. I am realizing (Unity3d) the moving forward (in the plane which is made by X- and Z-axis) using Rigidbody.velocity, the direction depends on MyPlayer.transform.localEulerAngles.y. Tell me, please:
Which of the realizations of the method for the button which moves (it will be called every frame if the button is pressed) is "cheaper":
a)
public void MoveForward()
{
PlayerRigidbody.velocity = new Vector3(speed * (float)(Math.Sin(((double)(transform.localEulerAngles.y / 180)) * Math.PI)), PlayerRigidbody.velocity.y, speed * (float)(Math.Cos(((double)(transform.localEulerAngles.y / 180)) * Math.PI)));
}
b)
public void MoveForward()
{
Quaternion rotation = Quaternion.AngleAxis((transform.localEulerAngles.y - 180), Vector3.up);
Vector3 temp = new Vector3(0, PlayerRigidbody.velocity.y, -speed);
PlayerRigidbody.velocity = rotation * temp;
}
Is there any dependency on Time.deltaTime?
You're setting the velocity, so if you mean speed when you use speed then there shouldn't be any need to include Time.deltaTime.
As far as performance goes, (1) you can implement it both ways and profile to find out which takes longer, and (2) the difference is almost certainly negligible and you should go with whatever is easier to read, because readability is key to maintainability.
Regarding point 2, IMO neither option is readable. Are you just trying to make the thing move in its local forward direction? Try using the TransformDirection method, like:
PlayerRigidbody.velocity = speed*transform.TransformDirection(Vector3.forward);
transform.TransformDirection says,
Description
Transforms direction from local space to world space.
so just pass that function the Vector3.forward and let Unity's built-in method handle the math.

1st person space ship pitch and yaw isue

I've been trying for some time now with different tutorials to get a nice firstperson (cockpit view) spaceship controll system. I tried using mouse only, keyboard only and combinations but I keep encountering the same problem with all tutorials. even this simple line of code does it:
transform.position += transform.forward * Time.deltaTime * 90f;
transform.Rotate( Input.GetAxis("Vertical"), Input.GetAxis("Horizontal"), 0.0f);
The problem I keep getting is that if I pitch its ok. it I yaw its ok. But If I do both (so I go diagonaly) it also rotates my ship on the Z axis and messes up my orientation. I tried locking the z rotation in the rigidbody but that does'nt help either. I tried making code myself alternating with apply torque and simply rotating, followed some tutorials including this one: Tutorial but keep getting the rotation problem.
What I want to make is a game that controlls like the old game Helbender
Does anyone of you know of a way that I can get spaceship controlls to work?
----EDIT-----
Got a bit further now. It doenst turn on my z axis anymore becouse I keep setting it to 0. Only problem now is that if I try to make a looping the ship flips around instead of nicely looping.
if (Input.GetKey("up"))
{
transform.Rotate(transform.right * -ShipPanSpeed * Time.deltaTime, Space.World);
}
if (Input.GetKey("down"))
{
transform.Rotate(transform.right * ShipPanSpeed * Time.deltaTime, Space.World);
}
if (Input.GetKey("left"))
{
transform.Rotate(transform.up * -ShipPanSpeed * Time.deltaTime,Space.World);
}
if (Input.GetKey("right"))
{
transform.Rotate(transform.up * ShipPanSpeed * Time.deltaTime,Space.World);
}
float z = transform.eulerAngles.z;
transform.Rotate(0, 0, -z);
You could always try to make one parent object for the Controls and then a child object (the spaceshit) that you can rotate for the pivot but not attach any movement beside rotation.
What i mean is that you can rotate the parent on the Y axis to make it rotate and move the transform forward or backward at the same time. If you want to pivot up or down you can transform forward at the sametime you transform up/down multiplied with the axis you want to pivot with
Example:
private void Update(){
//PARENT--------------------------------------------
// MOVING FORWARD AND BACKWARD
transform.position += transform.forward * Input.GetAxis("Vertical") * speed * Time.deltaTime();
// MOVING RIGHT AND LEFT
transform.position += transform.right * Input.GetAxis("Horizontal") * speed * Time.deltaTime();
//PIVOT UP AND DOWN
transform.position += transform.up * -Input.GetAxis("Mouse Y") * speed * Time.deltaTime();
//ROTATE AROUND THE Y AXIS
tranform.Rotate(0f, Input.GetAxis("Horizontal") * rotationspeed, 0f);
}
For the spaceship (child) for the pivot i would recommend you to make a emptyobject and set the chip to lookAt that object based on the input axis you use to move up/down and forward/backward.
Hope this helped or at least gave you a idea of how to make it :)

Unity3D Input.GetAxis for Mouse not consistent

i am working on camera rotations based on mouseInput and i want it to have consistent sensitivity across all framerates. According to the unity documentation, the Input.GetAxis should be inherently framerate independent for the mouse movement.
What I am finding is that when i use the code below and change the framerate from 200+ to 30, the Input.GetAxis is returning very different outputs. For 200+ fps the GetAxis is low around like 2-5 where for 30 fps it is returning around 10-15 for the same mouse movements. Its causes a very drastic sensitivity difference in-game. Am i missing something? Thanks
public Rigidbody _playerRigidBody;
private Vector2 _lookInput;
private void Start()
{
//Application.targetFrameRate = 30;
}
private void Update()
{
_lookInput.x = Input.GetAxis("Mouse X");
}
void FixedUpdate()
{
var sensitivity = 300f;
var newPlayerRotation = _playerRigidBody.rotation * Quaternion.Euler(_lookInput.x * sensitivity * Vector3.up * Time.deltaTime);
_playerRigidBody.MoveRotation(newPlayerRotation);
}
}
I have tested everything in this little function and the only thing that causes the issue is the Input.GetAxis. Its inconsistent. Any ideas or solutions or workarounds?
"framerate independent" means the value is depend on the movement of the mouse, it doesn't mean the value is consistent.
For framerate = 200, value = 2-5 means the mouse move 2-5 points in 1/200 seconds.
So to get the move distance during 1 second use:
_lookInput.x = Input.GetAxis("Mouse X") / Time.deltaTime;

Jump height and gravity in unity

I'm new to Unity and use CharacterController.Move to move my character around. In my game world, 1 unit = 1 meter.
This works great, for example for speed: if I use a speed of 5, the character has a speed of 5m/s.
I make my character jump using:
if (Input.GetButton("Jump"))
moveDirection.y = jumpHeight;
...
moveDirection.y -= gravity * Time.deltaTime;
This works fine too, but since the gravity is pulling my character down, the jumpHeight isn't actually reached. For example, a jumpHeight of 8 result in a jump of something around 2.4 meters.
How can I change my code so jumpHeight represents the height the character will jump, even with the gravity pulling him down? Basically, with a jumpHeight of 8, I want my player to perform a jump of 8 meters.
According to physics, with an initial velocity of 8, the height would be 1.6 with a gravity of 20 (height = initialvelocity^2/(2*gravity)). If this indeed would be the height I'm seeing in-game, I could simply transform the formula, but I'm seeing a height of around 2.4 meters...
You're on the right track. I'm assuming you know the SUVAT equations.
Our knowns can be jumpheight (8) and timeToJumpApex (0.5f) <- You can change this to whatever, but 0.5f is a good start.
Time to jump apex is as the name implies, the time taken to hit the apex of a jump.
We now need to solve for the remaining variables needed, gravity and jump velocity. Gravity can be defined as such:
gravity = 2 * jumpheight / timeToJumpApex^2;
Jump velocity can be defined as such:
jumpVelocity = gravity * timeToJumpApex;
Then you can do:
if (Input.GetButton("Jump"))
moveDirection.y = jumpVelocity;
...
moveDirection.y -= gravity * Time.deltaTime;