

DEVLOG 1 - I FIXED the player movement in my enemy possession game
After two months of fine-tuning, I’ve overhauled the movement in Returner to find the perfect balance between weight and responsiveness. By implementing asymmetrical gravity for more controlled jumping, a multi-state running system that uses variable acceleration for realistic turns, and a high-momentum ledge-climbing mechanic, the gameplay flow is smoother than ever. The biggest takeaway from this polish phase was that "feel" is driven by art; using a data-driven animation system with modular transitions has allowed me to ensure the player never feels stuck, keeping the action fast-paced and fluid.
I’ve spent the last two months trapped in a cycle of never-ending tweaking. My target? The player movement system.
For those new here, I’m developing Returner, a Metroidvania where the core hook is possessing your enemies to steal their abilities for combat and traversal. But before you can feel powerful as an enemy, you have to feel good as the player.
I’ve spent a huge chunk of the last month polishing the "feel," and it’s finally coming together. Here’s a deep dive into the improvements I’ve made—I’d love to hear your feedback on these.

The Big Realization: Art Drives Feel
The biggest discovery I made is how much "smooth" movement actually depends on animation. No matter how good your greybox logic is, it’s incredibly difficult to capture weight and timing without proper visual feedback.
My advice: Get your art (or a very close draft) ready before you start the final polish on movement. You can't balance weight if you can't see the character's center of gravity shifting.
1. Running: Weight vs. Responsiveness
The goal is simple: Smooth and responsive. I hate games where it feels like I’m fighting the controls or getting mauled by an enemy because I’m stuck in a non-cancellable animation.
Initially, I had one "running" state. It was stiff. Now, the system is broken into specific states to create variety:
Turning State: When the player changes direction.
Moving State: Active when x-velocity is > 0.
Wall Leap State: A quality-of-life feature for minor elevations.
The "Turn" Dilemma: If I keep the player's velocity at zero during a turn animation, the delay feels laggy. If I move at full speed, it looks like they’re sliding on ice.
** My Solution:** I now scale acceleration based on the previous state. If you turn from a standstill, the speed ramps up slowly. If you’re at a full sprint and pull a 180°, you maintain a bit of momentum (a "slide") for a brief moment before the speed ramps up in the new direction. To keep it precise, this only happens if you’ve been running long enough to build that momentum—otherwise, you stop on a dime.
The Wall Leap:
Inspired by Silksong, I added a feature where the player automatically scales tiny elevations while running. It keeps the flow alive so you aren't constantly jumping over "pebbles" in the level design.
2. Jumping: "Cheating" Gravity
Getting a jump to feel right is a nightmare. To stop the character from feeling like a floaty balloon or a lead weight, I’ve implemented a few "cheats":
Asymmetrical Gravity: The gravity applied while falling is actually less than the gravity applied while jumping. This helps the player reach the peak of their jump quickly (to hit targets) but gives them more "air time" on the way down to precisely position their landing.
Fall Move Multiplier: I slightly increase the horizontal speed ($x$-velocity) while falling. It’s subtle, but it makes the character feel much more reactive in mid-air.
Instant Take-off: To maximize responsiveness, the $y$-velocity hits its maximum the frame you press the button. No ramp-up. However, I do ramp up the fall velocity to create a tiny bit of "hang time" at the apex.
3. The Ledge Climb Headache
This was the hardest mechanic to get right. It required a mix of two shapecasts and two raycasts to detect consistently:
Head Shapecast: Checks if there is a ceiling. If yes, no climb.
Chest Shapecast: Checks for a wall in front of the player.
Floor Raycast: If the first two pass, this raycast fires downward to find the exact $y$-coordinate of the ledge's top surface.
Intentionality is Key: I originally automated this, but it kept interrupting combat. Now, the game only triggers a ledge climb if you are holding the forward direction.
Keeping Momentum:
Most games reset you to an "Idle" state after a climb. To keep Returner fast-paced, I added:
Ledge Canceling: You can jump mid-climb to perform a "wall kick" in the opposite direction (think Assassin’s Creed).
Input Buffering: If you’re holding "Forward" or "Attack" during the climb, the game skips the Idle animation entirely and transitions seamlessly into a run or strike the moment your feet hit the ledge.
4. The Technical Secret: Data-Driven Animation
To make this all work without creating 5,000 unique animations, I use a Start → Loop → End system.
Instead of the animation file determining the timing, my code drives the animation duration. If a move needs to be faster based on a buff or a specific state, the code just speeds up the loop or cuts to the "End" frames. This allows me to cancel any state midpoint and transition to a new one without the visuals looking "snappy" or broken.
What’s Next?
Returner is still early in development, and I need your help. I’m looking for testers to jump in and help me break these movement mechanics so I can make them even better.
Want to help? Join our [Discord Channel] to stay updated on the next playtest!
See you in the next one.