





Weekly Progress Report #77
This week I was finally able to root cause an issue that I've noticed intermittently for a long time: occasionally when you're playing, you'll be jumping normally, and all of a sudden you'll land, charge up a jump, and lose all of your momentum. In order to fully explain this issue, lets go into some detail about how the momentum system works, and how some specific unity quirks were causing these problems.
Intuition would say that if you need the character's velocity when you hit something, then just check the velocity when you hit it. Unfortunately if you try that with Unity, you'll realize things don't work that way. On a given physics step of the game, Unity updates the positions and velocities of all objects that are controlled by the physics system. At the end of the physics step, Unity triggers the collision detection methods (OnCollisionEnter, OnCollisionStay, OnCollisionExit), based on the positions & speeds after the calculations have been completed. What this means is that if you have an object going 10m/s that hits a wall, by the time you are told by Unity that it hit a wall, it's speed would already be set to what it is after it bounced off the wall. To compensate for that fact, PogoChamp uses a rolling window of recent speeds. Typically you'd only need the previous frame's speed, but due to the unpredictability of some of the collision behavior, I use a window of around 15 updates (0.3 seconds). When your character lands on a surface, the jump force is the maximum velocity within that time window, with scaling factors based on angle of impact, whether you're on a wall, and various other factors. In order to properly do the scaling, I store information about the collision at the time of impact.
During my investigation I noticed that very occasionally, the collision object I was storing would change its internal values to reference completely different objects. This was something I'd never noticed before, but I guess Unity reuses the allocated Collision objects, and doesn't guarantee anything about collisions beyond the frame that they were first created. This could occasionally result in a bounce where by the time your character was ready to jump, the collision it was using for momentum scaling had changed to a different collision, and you'd end up with a default strength jump no matter how fast you were moving before. To fix this, instead of storing the reference to the previous Collision, I now store a struct with the values I care about (mostly the collision normal).
The other "dud jump" bug was related to the way I calculate whether you are jumping manually or due to a bounce. There's special logic to "fake" a bounce with some default values so that I can reuse the same logic for manual and automatic bounces. Unfortunately I was a little inconsistent with how I was using the Update and FixedUpdate methods, and my naiive understanding of resolution order when it came to Collision detection bit my pretty badly. I assumed that OnCollisionEnter triggered before FixedUpdate during the physics loop, but it actually happens after. Here's a summary of the steps that were causing the bug. 1. [End Of Physics Loop] Unity detects a collision and registers the character as being "on the ground". 2. [Update Loop] My code detects that you are on the ground but not bouncing, so resets your landing velocity and starts a manual bounce. 3. [Physics Loop] My code calculates your bounce force with the newly reset velocity. What this meant in practice was that if the update loop ran between the time the landing was detected and the physics loop ran, your character would do a default strength jump. It's actually surprising to me this issue didn't happen more often in practice, given that the physics loop runs 50 times per second and the update loop runs much more often. The fix to this was to properly move step 2 of the FixedUpdate method, which worked great, except when I messed up the logic on an if/else branch and completely broke swimming for 20 hours... That is fixed now though.
[ 2022-03-12 16:04:09 CET ] [ Original post ]
I'm hard at work on the final level stuff! It's coming along pretty nicely, so expect to see it pretty soon! I also made some important bug fixes this week which I released early.
"Dud Jumps" Bugs
This week I was finally able to root cause an issue that I've noticed intermittently for a long time: occasionally when you're playing, you'll be jumping normally, and all of a sudden you'll land, charge up a jump, and lose all of your momentum. In order to fully explain this issue, lets go into some detail about how the momentum system works, and how some specific unity quirks were causing these problems.
Pogo Momentum
Intuition would say that if you need the character's velocity when you hit something, then just check the velocity when you hit it. Unfortunately if you try that with Unity, you'll realize things don't work that way. On a given physics step of the game, Unity updates the positions and velocities of all objects that are controlled by the physics system. At the end of the physics step, Unity triggers the collision detection methods (OnCollisionEnter, OnCollisionStay, OnCollisionExit), based on the positions & speeds after the calculations have been completed. What this means is that if you have an object going 10m/s that hits a wall, by the time you are told by Unity that it hit a wall, it's speed would already be set to what it is after it bounced off the wall. To compensate for that fact, PogoChamp uses a rolling window of recent speeds. Typically you'd only need the previous frame's speed, but due to the unpredictability of some of the collision behavior, I use a window of around 15 updates (0.3 seconds). When your character lands on a surface, the jump force is the maximum velocity within that time window, with scaling factors based on angle of impact, whether you're on a wall, and various other factors. In order to properly do the scaling, I store information about the collision at the time of impact.
Previous Collision Inconsistency
During my investigation I noticed that very occasionally, the collision object I was storing would change its internal values to reference completely different objects. This was something I'd never noticed before, but I guess Unity reuses the allocated Collision objects, and doesn't guarantee anything about collisions beyond the frame that they were first created. This could occasionally result in a bounce where by the time your character was ready to jump, the collision it was using for momentum scaling had changed to a different collision, and you'd end up with a default strength jump no matter how fast you were moving before. To fix this, instead of storing the reference to the previous Collision, I now store a struct with the values I care about (mostly the collision normal).
Update vs FixedUpdate
The other "dud jump" bug was related to the way I calculate whether you are jumping manually or due to a bounce. There's special logic to "fake" a bounce with some default values so that I can reuse the same logic for manual and automatic bounces. Unfortunately I was a little inconsistent with how I was using the Update and FixedUpdate methods, and my naiive understanding of resolution order when it came to Collision detection bit my pretty badly. I assumed that OnCollisionEnter triggered before FixedUpdate during the physics loop, but it actually happens after. Here's a summary of the steps that were causing the bug. 1. [End Of Physics Loop] Unity detects a collision and registers the character as being "on the ground". 2. [Update Loop] My code detects that you are on the ground but not bouncing, so resets your landing velocity and starts a manual bounce. 3. [Physics Loop] My code calculates your bounce force with the newly reset velocity. What this meant in practice was that if the update loop ran between the time the landing was detected and the physics loop ran, your character would do a default strength jump. It's actually surprising to me this issue didn't happen more often in practice, given that the physics loop runs 50 times per second and the update loop runs much more often. The fix to this was to properly move step 2 of the FixedUpdate method, which worked great, except when I messed up the logic on an if/else branch and completely broke swimming for 20 hours... That is fixed now though.
Changelog
- BUG FIX: Fix a couple different bugs that resulted in improperly weak jumps in certain situations.
- DEV: Update Level Select to handle the final levels.
- BUG FIX: Fix camera movement bug when you teleport after moving quickly in the Level Select.
- DEV: A bunch of bug fixes related to things you don't know about yet (related to the final level).
- BUG FIX: Disable They See Me Rollin' achievement when you "jump" with the bazooka.
- BUG FIX: Daily challenge now properly displays an error when it fails to load in certain ways.
- BUG FIX: Daily challenge now loads properly (JSONUtility can't serialize Dictionaries...)
- UX: Rename "Upload Gameplay Data" option to "Upload Error Logs", and remove the normal metrics uploads because I wasn't looking at them anyway.
- UX: Remove tooltip from "Upload Error Logs" option.
- BUG FIX: Crash logs upload properly again (another JSONUtility problem).
- DEV: Lots of work on the final level stuff. It's coming along nicely, but I don't want to spoil anything.
[ 2022-03-12 16:04:09 CET ] [ Original post ]
PogoChamp
Jake Rabinowitz
Developer
Jake Rabinowitz
Publisher
2021-04-12
Release
Game News Posts:
65
🎹🖱️Keyboard + Mouse
🎮 Full Controller Support
🎮 Full Controller Support
Positive
(21 reviews)
Game is not tagged as available on Linux on Steam.
Linux is not in the OS list.
I thought "PogoChamp" was a pretty good pun, so I spent a few thousand hours making a game around it...![]()
Features
- Unique, easy-to-understand, but tricky to master controls.
- Fluid, momentum-based movement (once you get the hang of it).
- 100 levels that constantly remix and iterate on the mechanics.
- Whacky power-ups that change how you play the game but still maintain the essential controls like: Fish Hat, Hamster Ball, Jetpack, Football, and Bazooka.
- A dedicated self-destruct button!
- Varied levels that are designed to be fun and surprising, for example: Pachinko, A Bullfight, Skee-Ball, Giant Mini Golf, A giant video game console, A Piano and more!
- Fully featured In-game Replay System that will show all of your attempts at once.
- Steam Leaderboards for every level. Leaderboard entries include replays so you can learn from the best!
- Multiple challenge target times for each level.
- Steam Achievements.
- 3 Different game modes: Standard, Survival, and Daily Challenge.
- Support for Keyboard & Mouse, Xbox, Playstation, Switch Pro, and generic gamepad controllers.
- Lots of puns!
- No dialog!
- Secret completionist objectives.
- A deliberate focus on being more fun than frustrating.
GAMEBILLET
[ 5965 ]
GAMERSGATE
[ 1690 ]
MacGamestore
[ 1915 ]
FANATICAL BUNDLES
HUMBLE BUNDLES
by buying games/dlcs from affiliate links you are supporting tuxDB