英文:
Game does not take input from keyboard consistantly
问题
我是新手游戏开发者,从YouTube上的7小时免费课程开始入门。我非常仔细地按照课程操作,但遇到了这个问题。据我目前学到的知识,这是当我按下空格键时使2D游戏对象跳跃的方法:
void PlayerJump()
{
if (Input.GetButtonDown("Jump") && isGrounded)
{
MyBody.AddForce(new Vector2(0f, jumpForce), ForceMode2D.Impulse);
}
}
但当我编译并运行我的游戏时,游戏对象并没有立刻跳跃,而是需要按了大约5、6次空格键才会跳跃一次,以后每次都需要按相同数量的次数。我不确定这是否是一个输入问题。在此之前,我保证没有漏掉课程中的任何内容。
我查找了可能存在于我的代码中的错误,但它看起来很干净。我期望按下空格键时立刻使它跳跃。
英文:
I am new to Game dev and started with the 7-hour free course on youtube. I followed the course very carefully and stumbled against this problem. As i have learn so far this is how to get the 2D game object to jump when i press Space:
void PlayerJump()
{
if (Input.GetButtonDown("Jump") && isGrounded)
{
MyBody.AddForce(new Vector2(0f, jumpForce), ForceMode2D.Impulse);
}
}
But when i compiled and run my game, the game object did not jump right away when i pressed Space. It took about 5,6 times to make it jump once, and about the same amount each time later. I'm not sure if this is an Input problem. I swear I did not miss anything in the course until this.
I looked for mistake i might have in my code and it's clean. I expect to make it jump right when i press Space
答案1
得分: 1
以下是您要翻译的代码部分:
// Update is called once per frame
void Update()
{
PlayerMoveKeyboard();
AnimatePlayer();
if (Input.GetButtonDown("Jump"))
{
Debug.Log("pressedUpdate" + isGrounded);
}
}
private void FixedUpdate()
{
PlayerJump();
}
void PlayerJump()
{
if (Input.GetButtonDown("Jump"))
{
Debug.Log("pressedFixed" + isGrounded);
}
if (Input.GetButtonDown("Jump") && isGrounded)
{
Debug.Log("jump");
isGrounded = false;
myBody.AddForce(new Vector2(0f, jumpForce), ForceMode2D.Impulse);
}
}
private bool jump;
[SerializeField] private float lenience = 0.2f;
// Update is called once per frame
void Update()
{
PlayerMoveKeyboard();
AnimatePlayer();
JumpInput();
}
private void FixedUpdate()
{
PlayerJump();
}
void JumpInput()
{
if (Input.GetButtonDown("Jump"))
{
CancelInvoke("Lenience");
jump = true;
Invoke("Lenience", lenience);
}
}
private void Lenience()
{
jump = false;
}
private void CancelLenience()
{
CancelInvoke("Lenience");
jump = false;
}
void PlayerJump()
{
if (jump && isGrounded)
{
CancelLenience();
isGrounded = false;
myBody.AddForce(new Vector2(0f, jumpForce), ForceMode2D.Impulse);
}
}
英文:
First I would like to demonstrate that the code from the tutorial does indeed miss valid space bar presses.
// Update is called once per frame
void Update()
{
PlayerMoveKeyboard();
AnimatePlayer();
if (Input.GetButtonDown("Jump"))
{
Debug.Log("pressedUpdate" + isGrounded);
}
}
private void FixedUpdate()
{
PlayerJump();
}
void PlayerJump()
{
if (Input.GetButtonDown("Jump"))
{
Debug.Log("pressedFixed" + isGrounded);
}
if (Input.GetButtonDown("Jump") && isGrounded)
{
Debug.Log("jump");
isGrounded = false;
myBody.AddForce(new Vector2(0f, jumpForce), ForceMode2D.Impulse);
}
}
If you compile this and play around for a bit you can get the following output in the log:
As you can see the update loop has detected the button press 6 times and only on the last one the fixed update loop detected the input and executed the jump.
Something you need to know is that Input.GetButtonDown
is only true for the frame that it is pressed down. By default Unity runs in 60 fps and therefore the input system is checked approximately every 0.017 seconds. When you press the space bar the input system learns about that on the next frame. For the next 0.017 seconds the button is considered to be pressed down.
Parallel to this FixedUpdate
is called every 0.02 seconds (default time step), which is a little bit more than the duration of a frame.
Consider the following scenario:
- Unity checks the input in the
FixedUpdate
and detects that space wasn't pressed yet - runs the frame related code and the input system detects that space is pressed down
- 0.017 seconds pass and it's time for the next frame where the input system decides that the button is no longer pressed down, but rather held down
- since 0.02 seconds have passed now Unity quickly goes back to check on the
FixedUpdate
, queries the input system once more, which reports that the button wasn't pressed down
Depending on your timing pressing the button this can happen a number of times in a row, or not happen at all.
The lazy solution would be so simply decrease the physics time step to be smaller than the frame rate step. You can go to the Project Settings
in the Time
menu and set the Fixed Timestep
to something like 0.01. Problem with this approach is that you make physics more expensive and don't actually address the issue, since it will crawl back if you run the game in 120 fps for example.
Another easy solution is to simply move the the PlayerJump
function into the Update
loop. As the guy in the tutorial explained it is technically not correct to do this, since you should keep all physics related stuff in FixedUpdate
, but you won't notice the collision related issues in such a simple game.
Finlay there is the "proper" way to resolve your problem by implementing a lenience system with a bit more advanced code. Instead of the jump button only counting as pressed down for one frame you can make it so it is considered pressed down for an arbitrary long amount of time.
private bool jump;
[SerializeField] private float lenience = 0.2f;
// Update is called once per frame
void Update()
{
PlayerMoveKeyboard();
AnimatePlayer();
JumpInput();
}
private void FixedUpdate()
{
PlayerJump();
}
void JumpInput()
{
if (Input.GetButtonDown("Jump"))
{
CancelInvoke("Lenience");
jump = true;
Invoke("Lenience", lenience);
}
}
private void Lenience()
{
jump = false;
}
private void CancelLenience()
{
CancelInvoke("Lenience");
jump = false;
}
void PlayerJump()
{
if (jump && isGrounded)
{
CancelLenience();
isGrounded = false;
myBody.AddForce(new Vector2(0f, jumpForce), ForceMode2D.Impulse);
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论