Obstacle Course plays differently in Unity and Build Version

My Obstacle Course game is finished. As always, my version is quite different than the one in the course. I added a SPACE to JUMP inside my version.

When I play it inside the Unity software, the JUMP is very different. Most of the time it will not jump at all. Sometimes it jumps very low. It’s pretty random. However, I compiled it for the WEB and on the compiled version it behaves exactly as it should.

Any idea why the editor behaves differently than the compiled version?

Here is my github repo if you want to try it yourself.
https://github.com/JerryHobby/Obstacle-Course

Here is my compiled web-based version.
https://godot.jerryhobby.com/obstaclecourse/index.html

Hi Jerry,

Your title mentions Unreal, which is a different game engine than Unity. I assume you meant Unity because, otherwise, I won’t be able to help you with this problem as I don’t know Unreal.

From what I see in your Mover class, Time.deltaTime gets used with a Rigidbody method. That might explain why the player behaves differently depending on where/what you are playing. The Rigidbody is controlled by the physics simulation, and the physics simulation takes care of the framerate. Try to remove Time.deltaTime in your current solution, then test your game again.

Also consider using all Rigidbody methods in FixedUpdate because that’s the right place where those methods should be called according to Unity’s logic. Process the user input in Update.

I hope this helped. :slight_smile:


See also:

First off, thank you so much for everything. I appreciate your time and contribution to the community.

I made the updates as you suggested. The game plays exactly the same after a little tuning. But it also still had the problem that it plays differently in the editor than in the compiled version. So I kept testing.

Here’s what I found ---- for the JUMP functionality, I was using:
if (Input.GetKeyDown(KeyCode.Space))

I changed it to:
if (Input.GetKey(KeyCode.Space))

That made all the difference. There is some issue with the GetKeyDown function when running in the editor.

With that one change, the game plays exactly the same in the editor and in the build version.

Jerry

Good job on figuring the problem out. :slight_smile:

I completely forgot that the player might keep the spacebar pressed down. In that case, Move(Vector3.up); gets called only once. Since Unity’s framerate is inconsistent, you might get a noticeable difference when playing your game in the editor and in your browser.

The editor has got another problem, which is unsolveable: The game window is just a laggy preview. For this reason, if the lagging is too strong, it is usually a good idea to build the game and test the build to see if the actual game also lags. Don’t try to optimise your game for the editor because, in the end, only the build matters.

Anyway, doesn’t the player fly with if (Input.GetKey(KeyCode.Space))? I noticed this condition:
if (direction == Vector3.up && _rigidBody.velocity.y > 0). Theoretically, if your player falls down, the velocity.y value might be negative. If he presses the space key, wouldn’t he be able to jump despite not being on the ground? This is something you should test because that’s one of those typical bugs enthusiastic player try to find and exploit. :wink:

In this particular game, the line "if (direction == Vector3.up && _rigidBody.velocity.y > 0): is meant to prevent rapid jumping, which is what would occur with GetKey. Without some restriction, holding the space sends you to the moon. An alternative would be a timer or trigger function to prevent rapid repetition of jumping on every frame.

For this particular game, there’s no fall pit to jump out of, so it doesn’t expose a cheat. But the logic does feel rigged. Ideally when someone hits jump, it registered ONE time as a trigger and that causes a single jump. In Godot, I use Just Pressed to trigger a single action. That’s what is missing in my code. A reliable one-time-fire for the jump key.

That’s what I figured. :wink:

If you jump, you don’t stop in the air, though. At some point, you get a negative velocity due to the gravity which pulls you down. Even if it’s just for a brief moment, _rigidBody.velocity.y > 0 would get evaluated to false. That’s what I meant. If the player keeps hitting the space key fast enough, the result could be this:

image

Or did you add a condition for that case, too?


I’m still wondering why you did not achieve the desired result with if (Input.GetKeyDown(KeyCode.Space)). Maybe try direction.y = JumpSpeed; instead of direction.y *= JumpSpeed; as you probably don’t want to accellerate the player.

I’m relatively sure that you are able to achieve the desired result with Unity’s methods because you ‘just’ try to implement typical game mechanics. Unity would not be as popular as it is if typical game mechanics do not work well.

Here is an edited version of your Mover class. I outsourced the user input to Update to avoid data loss, and I simplified the code a bit because Unity has a shortcut for checking WASD and arrow keys. This modified structure will hopefully help you implement and test your ideas faster. Since I did not test the code, it might be that it does not work well.

Edited Mover class
using UnityEngine;

namespace Scenes.Player
{
    public class Mover : MonoBehaviour
    {
        private const float SPEED = 12f;
        private const float JUMP_SPEED = 200f;

        private Rigidbody _rigidBody;
        
        // user input
        private float _xInput, _yInput;
        private bool _shallJump;
        
        private void Start()
        {
            _rigidBody = GetComponent<Rigidbody>();
        }
        
       private void Update()
       {
            ProcessUserInput();
       }

        private void FixedUpdate()
        {
            Move();
        }

        private void ProcessUserInput()
        {
            // Alternatively, you can check all keys manually as you did
            // but the typical input keys are mapped to GetAxis.
            _xInput = Input.GetAxis("Horizontal");
            _yInput = Input.GetAxis("Vertical");
           
            _shallJump = Input.GetKeyDown(KeyCode.Space);
        }
    
        private void Move()
        {
            // Check if jumping
            // if player has y-velocity, he is jumping
            // and not allowed to move via key input
            if (Mathf.Abs(_rigidBody.velocity.y) > 0.01f) { return; }
            
            Vector3 movement = new Vector3(
                _xInput * SPEED,
                _shallJump ? JUMP_SPEED : 0f,
                _yInput * SPEED
            );

            _rigidBody.AddForce(movement);
            _shallJump = false;
        }
    }
}

I’m going to work on this later today and will update you.

How are you getting on with this, @JerryHobby? Were you able to solve the problem? :slight_smile:

The main reason - I suspect - is because the keypress is being checked in FixedUpdate. This means the keypress is only checked on physics intervals. Ideally, one would grab user input in the Update method, and act on those in the FixedUpdate (if you are using physics).

The update could run at as much as 300fps, but the physics update only happens at 60fps. This means there are roughly 50 game updates happening between each physics update. That’s 50 more places to check if the player hit the space key. 50 places where the player could have pressed and released the key before a physics update happens. Usually, you’d set a flag in Update to indicate if the player pressed the Jump key, and then reset it once you processed it. Like

private void Update()
{
    if (Input.GetKeyDown(KeyCode.Space))
    {
        isJumping = true;
    }
}

private void FixedUpdate()
{
    if (isJumping)
    {
        // Do a jump thing
        isJumping = false;
    }
}

Edit
Oh. Just looked at @Nina’s updated class. It does exactly this. Sorry for necro-ing a potential solution

No worries. I didn’t test my code, so it’s good to see that somebody else had the same idea as I. :slight_smile:

I waited to reply until after the migration to make sure everything posted as expected.

Yes, the solution was correct. As it turns out, the Update() function is not as reliable for keyboard input inside the development environment. The FixedUpdate() method is more reliable for that. While I didn’t use your code, I implemented the spirit of the solution and it worked great.

Thank you, and others, for contributing. It’s very helpful and greatly appreciated.

Jerry

You’re welcome. I’m glad we were able to help you fix the problem. :slight_smile:

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms